How can I expand a quoted variable to nothing if it's empty?
up vote
14
down vote
favorite
Say I have a script doing:
some-command "$var1" "$var2" ...
And, in the event that var1
is empty, I'd rather that it be replaced with nothing instead of the empty string, so that the command executed is:
some-command "$var2" ...
and not:
some-command '' "$var2" ...
Is there a simpler way than testing the variable and conditionally including it?
if [ -n "$1" ]; then
some-command "$var1" "$var2" ...
# or some variant using arrays to build the command
# args+=("$var1")
else
some-command "$var2" ...
fi
Is there a parameter substitution than can expand to nothing in bash, zsh, or the like? I might still want to use globbing in the rest of the arguments, so disabling that and unquoting the variable is not an option.
bash shell-script zsh variable
add a comment |
up vote
14
down vote
favorite
Say I have a script doing:
some-command "$var1" "$var2" ...
And, in the event that var1
is empty, I'd rather that it be replaced with nothing instead of the empty string, so that the command executed is:
some-command "$var2" ...
and not:
some-command '' "$var2" ...
Is there a simpler way than testing the variable and conditionally including it?
if [ -n "$1" ]; then
some-command "$var1" "$var2" ...
# or some variant using arrays to build the command
# args+=("$var1")
else
some-command "$var2" ...
fi
Is there a parameter substitution than can expand to nothing in bash, zsh, or the like? I might still want to use globbing in the rest of the arguments, so disabling that and unquoting the variable is not an option.
bash shell-script zsh variable
I knew I had seen and probably used this before, but it proved difficult to search. Now that Michael showed the syntax, I remembered where I'd first seen it quickly enough: unix.stackexchange.com/a/269549/70524, unix.stackexchange.com/q/68484/70524
– muru
Jan 10 at 7:25
If you know it is some kind of parameter substitution, why didn't you look into the parameter expansion section of theman
page? (-;
– Philippos
Jan 10 at 8:29
1
@Philippos I didn't know what it was at the time, only that I'd seen or used it before. Known knowns and unknown knowns. :(
– muru
Jan 10 at 8:33
1
extra cookie points for mentioning using an array to hold the arguments in the question itself.
– ilkkachu
Jan 10 at 15:12
add a comment |
up vote
14
down vote
favorite
up vote
14
down vote
favorite
Say I have a script doing:
some-command "$var1" "$var2" ...
And, in the event that var1
is empty, I'd rather that it be replaced with nothing instead of the empty string, so that the command executed is:
some-command "$var2" ...
and not:
some-command '' "$var2" ...
Is there a simpler way than testing the variable and conditionally including it?
if [ -n "$1" ]; then
some-command "$var1" "$var2" ...
# or some variant using arrays to build the command
# args+=("$var1")
else
some-command "$var2" ...
fi
Is there a parameter substitution than can expand to nothing in bash, zsh, or the like? I might still want to use globbing in the rest of the arguments, so disabling that and unquoting the variable is not an option.
bash shell-script zsh variable
Say I have a script doing:
some-command "$var1" "$var2" ...
And, in the event that var1
is empty, I'd rather that it be replaced with nothing instead of the empty string, so that the command executed is:
some-command "$var2" ...
and not:
some-command '' "$var2" ...
Is there a simpler way than testing the variable and conditionally including it?
if [ -n "$1" ]; then
some-command "$var1" "$var2" ...
# or some variant using arrays to build the command
# args+=("$var1")
else
some-command "$var2" ...
fi
Is there a parameter substitution than can expand to nothing in bash, zsh, or the like? I might still want to use globbing in the rest of the arguments, so disabling that and unquoting the variable is not an option.
bash shell-script zsh variable
bash shell-script zsh variable
edited Jan 10 at 8:26
Michael Homer
44.5k7117155
44.5k7117155
asked Jan 10 at 6:44
muru
34.8k580153
34.8k580153
I knew I had seen and probably used this before, but it proved difficult to search. Now that Michael showed the syntax, I remembered where I'd first seen it quickly enough: unix.stackexchange.com/a/269549/70524, unix.stackexchange.com/q/68484/70524
– muru
Jan 10 at 7:25
If you know it is some kind of parameter substitution, why didn't you look into the parameter expansion section of theman
page? (-;
– Philippos
Jan 10 at 8:29
1
@Philippos I didn't know what it was at the time, only that I'd seen or used it before. Known knowns and unknown knowns. :(
– muru
Jan 10 at 8:33
1
extra cookie points for mentioning using an array to hold the arguments in the question itself.
– ilkkachu
Jan 10 at 15:12
add a comment |
I knew I had seen and probably used this before, but it proved difficult to search. Now that Michael showed the syntax, I remembered where I'd first seen it quickly enough: unix.stackexchange.com/a/269549/70524, unix.stackexchange.com/q/68484/70524
– muru
Jan 10 at 7:25
If you know it is some kind of parameter substitution, why didn't you look into the parameter expansion section of theman
page? (-;
– Philippos
Jan 10 at 8:29
1
@Philippos I didn't know what it was at the time, only that I'd seen or used it before. Known knowns and unknown knowns. :(
– muru
Jan 10 at 8:33
1
extra cookie points for mentioning using an array to hold the arguments in the question itself.
– ilkkachu
Jan 10 at 15:12
I knew I had seen and probably used this before, but it proved difficult to search. Now that Michael showed the syntax, I remembered where I'd first seen it quickly enough: unix.stackexchange.com/a/269549/70524, unix.stackexchange.com/q/68484/70524
– muru
Jan 10 at 7:25
I knew I had seen and probably used this before, but it proved difficult to search. Now that Michael showed the syntax, I remembered where I'd first seen it quickly enough: unix.stackexchange.com/a/269549/70524, unix.stackexchange.com/q/68484/70524
– muru
Jan 10 at 7:25
If you know it is some kind of parameter substitution, why didn't you look into the parameter expansion section of the
man
page? (-;– Philippos
Jan 10 at 8:29
If you know it is some kind of parameter substitution, why didn't you look into the parameter expansion section of the
man
page? (-;– Philippos
Jan 10 at 8:29
1
1
@Philippos I didn't know what it was at the time, only that I'd seen or used it before. Known knowns and unknown knowns. :(
– muru
Jan 10 at 8:33
@Philippos I didn't know what it was at the time, only that I'd seen or used it before. Known knowns and unknown knowns. :(
– muru
Jan 10 at 8:33
1
1
extra cookie points for mentioning using an array to hold the arguments in the question itself.
– ilkkachu
Jan 10 at 15:12
extra cookie points for mentioning using an array to hold the arguments in the question itself.
– ilkkachu
Jan 10 at 15:12
add a comment |
3 Answers
3
active
oldest
votes
up vote
22
down vote
accepted
Posix compliant shells and Bash have ${parameter:+word}
:
If parameter is unset or null, null shall be substituted; otherwise, the expansion of word (or an empty string if word is omitted) shall be substituted.
So you can just do:
${var1:+"$var1"}
and have var1
be checked, and "$var1"
be used if it's set and non-empty (with the ordinary double-quoting rules). Otherwise it expands to nothing. Note that only the inner part is quoted here, not the whole thing.
The same also works in zsh. You have to repeat the variable, so it's not ideal, but it works out exactly as you wanted.
If you want a set-but-empty variable to expand to an empty argument, use ${var1+"$var1"}
instead.
1
Good enough for me. So, in this, the whole thing is not quoted, only theword
part is.
– muru
Jan 10 at 6:57
1
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
2
I took the liberty of editing in the difference between:+
and+
.
– ilkkachu
Jan 10 at 15:16
Thanks much for a POSIX-compliant solution! I try to usesh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.
– JamesTheAwesomeDude
May 29 at 20:19
add a comment |
up vote
3
down vote
That's what zsh
does by default when you omit the quotes:
some-command $var1 $var2
Actually, the only reason why you still need quotes in zsh around parameter expansion is to avoid that behaviour (the empty removal) as zsh
doesn't have the other problems that affect other shells when you don't quote parameter expansions (the implicit split+glob).
You can do the same with other POSIX-like shells if you disable split and glob:
(IFS=; set -o noglob; some-command $var1 $var2)
Now, I'd argue that if your variable can have either 0 or 1 value, it should be an array and not a scalar variable and use:
some-command "${var1[@]}" "${var2[@]}"
And use var1=(value)
when var1
is to contain one value, var1=('')
when it's to contain one empty value, and var1=()
when it's to contain no value.
add a comment |
up vote
0
down vote
I ran into this using rsync in a bash script that started the command with or without a -n
to toggle dry runs. It turns out that rsync and a number of gnu commands take ''
as a valid first argument and act differently than if it were not there.
This took quite awhile to debug as null parameters are almost completely invisible.
Someone on the rsync list showed me a way to avoid this problem while also greatly simplifying my coding. If I understand it correctly, this is a variation on @Stéphane Chazelas's last suggestion.
Build your command arguments in a number of separate variables. These can be set in any order or logic that suits the problem.
Then, at the end, use the variables to construct an array with everything in its proper place and use that as arguments to the actual command.
This way the command is only issued at one place in the code instead of being repeated for each variation of the arguments.
Any variable that is empty just disappears using this method.
I know using eval is highly frowned upon. I don't remember all the details, but I seemed to need it to get things to work this way - something to do with handling parameters with embedded white space.
Example:
dry_run=''
if [[ it is a test run ]]
then
dry_run='-n'
fi
...
rsync_options=(
${dry_run}
-avushi
${delete}
${excludes}
--stats
--progress
)
...
eval rsync "${rsync_options[@]}" ...
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
22
down vote
accepted
Posix compliant shells and Bash have ${parameter:+word}
:
If parameter is unset or null, null shall be substituted; otherwise, the expansion of word (or an empty string if word is omitted) shall be substituted.
So you can just do:
${var1:+"$var1"}
and have var1
be checked, and "$var1"
be used if it's set and non-empty (with the ordinary double-quoting rules). Otherwise it expands to nothing. Note that only the inner part is quoted here, not the whole thing.
The same also works in zsh. You have to repeat the variable, so it's not ideal, but it works out exactly as you wanted.
If you want a set-but-empty variable to expand to an empty argument, use ${var1+"$var1"}
instead.
1
Good enough for me. So, in this, the whole thing is not quoted, only theword
part is.
– muru
Jan 10 at 6:57
1
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
2
I took the liberty of editing in the difference between:+
and+
.
– ilkkachu
Jan 10 at 15:16
Thanks much for a POSIX-compliant solution! I try to usesh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.
– JamesTheAwesomeDude
May 29 at 20:19
add a comment |
up vote
22
down vote
accepted
Posix compliant shells and Bash have ${parameter:+word}
:
If parameter is unset or null, null shall be substituted; otherwise, the expansion of word (or an empty string if word is omitted) shall be substituted.
So you can just do:
${var1:+"$var1"}
and have var1
be checked, and "$var1"
be used if it's set and non-empty (with the ordinary double-quoting rules). Otherwise it expands to nothing. Note that only the inner part is quoted here, not the whole thing.
The same also works in zsh. You have to repeat the variable, so it's not ideal, but it works out exactly as you wanted.
If you want a set-but-empty variable to expand to an empty argument, use ${var1+"$var1"}
instead.
1
Good enough for me. So, in this, the whole thing is not quoted, only theword
part is.
– muru
Jan 10 at 6:57
1
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
2
I took the liberty of editing in the difference between:+
and+
.
– ilkkachu
Jan 10 at 15:16
Thanks much for a POSIX-compliant solution! I try to usesh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.
– JamesTheAwesomeDude
May 29 at 20:19
add a comment |
up vote
22
down vote
accepted
up vote
22
down vote
accepted
Posix compliant shells and Bash have ${parameter:+word}
:
If parameter is unset or null, null shall be substituted; otherwise, the expansion of word (or an empty string if word is omitted) shall be substituted.
So you can just do:
${var1:+"$var1"}
and have var1
be checked, and "$var1"
be used if it's set and non-empty (with the ordinary double-quoting rules). Otherwise it expands to nothing. Note that only the inner part is quoted here, not the whole thing.
The same also works in zsh. You have to repeat the variable, so it's not ideal, but it works out exactly as you wanted.
If you want a set-but-empty variable to expand to an empty argument, use ${var1+"$var1"}
instead.
Posix compliant shells and Bash have ${parameter:+word}
:
If parameter is unset or null, null shall be substituted; otherwise, the expansion of word (or an empty string if word is omitted) shall be substituted.
So you can just do:
${var1:+"$var1"}
and have var1
be checked, and "$var1"
be used if it's set and non-empty (with the ordinary double-quoting rules). Otherwise it expands to nothing. Note that only the inner part is quoted here, not the whole thing.
The same also works in zsh. You have to repeat the variable, so it's not ideal, but it works out exactly as you wanted.
If you want a set-but-empty variable to expand to an empty argument, use ${var1+"$var1"}
instead.
edited Jan 10 at 15:16
ilkkachu
53.7k781146
53.7k781146
answered Jan 10 at 6:51
Michael Homer
44.5k7117155
44.5k7117155
1
Good enough for me. So, in this, the whole thing is not quoted, only theword
part is.
– muru
Jan 10 at 6:57
1
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
2
I took the liberty of editing in the difference between:+
and+
.
– ilkkachu
Jan 10 at 15:16
Thanks much for a POSIX-compliant solution! I try to usesh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.
– JamesTheAwesomeDude
May 29 at 20:19
add a comment |
1
Good enough for me. So, in this, the whole thing is not quoted, only theword
part is.
– muru
Jan 10 at 6:57
1
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
2
I took the liberty of editing in the difference between:+
and+
.
– ilkkachu
Jan 10 at 15:16
Thanks much for a POSIX-compliant solution! I try to usesh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.
– JamesTheAwesomeDude
May 29 at 20:19
1
1
Good enough for me. So, in this, the whole thing is not quoted, only the
word
part is.– muru
Jan 10 at 6:57
Good enough for me. So, in this, the whole thing is not quoted, only the
word
part is.– muru
Jan 10 at 6:57
1
1
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
As the question asked for "bash, zsh, or the like" (and for the Q&A archive), I edited to reflect that this is a posix feature. Even, if you add a /bash tag to the question after my comment. (-;
– Philippos
Jan 10 at 8:25
2
2
I took the liberty of editing in the difference between
:+
and +
.– ilkkachu
Jan 10 at 15:16
I took the liberty of editing in the difference between
:+
and +
.– ilkkachu
Jan 10 at 15:16
Thanks much for a POSIX-compliant solution! I try to use
sh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.– JamesTheAwesomeDude
May 29 at 20:19
Thanks much for a POSIX-compliant solution! I try to use
sh
/dash
for potential chokepoint scripts, so I always appreciate it when someone shows how a thing is possible without resorting to Bash.– JamesTheAwesomeDude
May 29 at 20:19
add a comment |
up vote
3
down vote
That's what zsh
does by default when you omit the quotes:
some-command $var1 $var2
Actually, the only reason why you still need quotes in zsh around parameter expansion is to avoid that behaviour (the empty removal) as zsh
doesn't have the other problems that affect other shells when you don't quote parameter expansions (the implicit split+glob).
You can do the same with other POSIX-like shells if you disable split and glob:
(IFS=; set -o noglob; some-command $var1 $var2)
Now, I'd argue that if your variable can have either 0 or 1 value, it should be an array and not a scalar variable and use:
some-command "${var1[@]}" "${var2[@]}"
And use var1=(value)
when var1
is to contain one value, var1=('')
when it's to contain one empty value, and var1=()
when it's to contain no value.
add a comment |
up vote
3
down vote
That's what zsh
does by default when you omit the quotes:
some-command $var1 $var2
Actually, the only reason why you still need quotes in zsh around parameter expansion is to avoid that behaviour (the empty removal) as zsh
doesn't have the other problems that affect other shells when you don't quote parameter expansions (the implicit split+glob).
You can do the same with other POSIX-like shells if you disable split and glob:
(IFS=; set -o noglob; some-command $var1 $var2)
Now, I'd argue that if your variable can have either 0 or 1 value, it should be an array and not a scalar variable and use:
some-command "${var1[@]}" "${var2[@]}"
And use var1=(value)
when var1
is to contain one value, var1=('')
when it's to contain one empty value, and var1=()
when it's to contain no value.
add a comment |
up vote
3
down vote
up vote
3
down vote
That's what zsh
does by default when you omit the quotes:
some-command $var1 $var2
Actually, the only reason why you still need quotes in zsh around parameter expansion is to avoid that behaviour (the empty removal) as zsh
doesn't have the other problems that affect other shells when you don't quote parameter expansions (the implicit split+glob).
You can do the same with other POSIX-like shells if you disable split and glob:
(IFS=; set -o noglob; some-command $var1 $var2)
Now, I'd argue that if your variable can have either 0 or 1 value, it should be an array and not a scalar variable and use:
some-command "${var1[@]}" "${var2[@]}"
And use var1=(value)
when var1
is to contain one value, var1=('')
when it's to contain one empty value, and var1=()
when it's to contain no value.
That's what zsh
does by default when you omit the quotes:
some-command $var1 $var2
Actually, the only reason why you still need quotes in zsh around parameter expansion is to avoid that behaviour (the empty removal) as zsh
doesn't have the other problems that affect other shells when you don't quote parameter expansions (the implicit split+glob).
You can do the same with other POSIX-like shells if you disable split and glob:
(IFS=; set -o noglob; some-command $var1 $var2)
Now, I'd argue that if your variable can have either 0 or 1 value, it should be an array and not a scalar variable and use:
some-command "${var1[@]}" "${var2[@]}"
And use var1=(value)
when var1
is to contain one value, var1=('')
when it's to contain one empty value, and var1=()
when it's to contain no value.
edited Jan 14 at 9:24
answered Jan 11 at 22:05
Stéphane Chazelas
293k54551893
293k54551893
add a comment |
add a comment |
up vote
0
down vote
I ran into this using rsync in a bash script that started the command with or without a -n
to toggle dry runs. It turns out that rsync and a number of gnu commands take ''
as a valid first argument and act differently than if it were not there.
This took quite awhile to debug as null parameters are almost completely invisible.
Someone on the rsync list showed me a way to avoid this problem while also greatly simplifying my coding. If I understand it correctly, this is a variation on @Stéphane Chazelas's last suggestion.
Build your command arguments in a number of separate variables. These can be set in any order or logic that suits the problem.
Then, at the end, use the variables to construct an array with everything in its proper place and use that as arguments to the actual command.
This way the command is only issued at one place in the code instead of being repeated for each variation of the arguments.
Any variable that is empty just disappears using this method.
I know using eval is highly frowned upon. I don't remember all the details, but I seemed to need it to get things to work this way - something to do with handling parameters with embedded white space.
Example:
dry_run=''
if [[ it is a test run ]]
then
dry_run='-n'
fi
...
rsync_options=(
${dry_run}
-avushi
${delete}
${excludes}
--stats
--progress
)
...
eval rsync "${rsync_options[@]}" ...
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
add a comment |
up vote
0
down vote
I ran into this using rsync in a bash script that started the command with or without a -n
to toggle dry runs. It turns out that rsync and a number of gnu commands take ''
as a valid first argument and act differently than if it were not there.
This took quite awhile to debug as null parameters are almost completely invisible.
Someone on the rsync list showed me a way to avoid this problem while also greatly simplifying my coding. If I understand it correctly, this is a variation on @Stéphane Chazelas's last suggestion.
Build your command arguments in a number of separate variables. These can be set in any order or logic that suits the problem.
Then, at the end, use the variables to construct an array with everything in its proper place and use that as arguments to the actual command.
This way the command is only issued at one place in the code instead of being repeated for each variation of the arguments.
Any variable that is empty just disappears using this method.
I know using eval is highly frowned upon. I don't remember all the details, but I seemed to need it to get things to work this way - something to do with handling parameters with embedded white space.
Example:
dry_run=''
if [[ it is a test run ]]
then
dry_run='-n'
fi
...
rsync_options=(
${dry_run}
-avushi
${delete}
${excludes}
--stats
--progress
)
...
eval rsync "${rsync_options[@]}" ...
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
add a comment |
up vote
0
down vote
up vote
0
down vote
I ran into this using rsync in a bash script that started the command with or without a -n
to toggle dry runs. It turns out that rsync and a number of gnu commands take ''
as a valid first argument and act differently than if it were not there.
This took quite awhile to debug as null parameters are almost completely invisible.
Someone on the rsync list showed me a way to avoid this problem while also greatly simplifying my coding. If I understand it correctly, this is a variation on @Stéphane Chazelas's last suggestion.
Build your command arguments in a number of separate variables. These can be set in any order or logic that suits the problem.
Then, at the end, use the variables to construct an array with everything in its proper place and use that as arguments to the actual command.
This way the command is only issued at one place in the code instead of being repeated for each variation of the arguments.
Any variable that is empty just disappears using this method.
I know using eval is highly frowned upon. I don't remember all the details, but I seemed to need it to get things to work this way - something to do with handling parameters with embedded white space.
Example:
dry_run=''
if [[ it is a test run ]]
then
dry_run='-n'
fi
...
rsync_options=(
${dry_run}
-avushi
${delete}
${excludes}
--stats
--progress
)
...
eval rsync "${rsync_options[@]}" ...
I ran into this using rsync in a bash script that started the command with or without a -n
to toggle dry runs. It turns out that rsync and a number of gnu commands take ''
as a valid first argument and act differently than if it were not there.
This took quite awhile to debug as null parameters are almost completely invisible.
Someone on the rsync list showed me a way to avoid this problem while also greatly simplifying my coding. If I understand it correctly, this is a variation on @Stéphane Chazelas's last suggestion.
Build your command arguments in a number of separate variables. These can be set in any order or logic that suits the problem.
Then, at the end, use the variables to construct an array with everything in its proper place and use that as arguments to the actual command.
This way the command is only issued at one place in the code instead of being repeated for each variation of the arguments.
Any variable that is empty just disappears using this method.
I know using eval is highly frowned upon. I don't remember all the details, but I seemed to need it to get things to work this way - something to do with handling parameters with embedded white space.
Example:
dry_run=''
if [[ it is a test run ]]
then
dry_run='-n'
fi
...
rsync_options=(
${dry_run}
-avushi
${delete}
${excludes}
--stats
--progress
)
...
eval rsync "${rsync_options[@]}" ...
answered Jan 13 at 4:52
Joe
935816
935816
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
add a comment |
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
That's a worse way of doing what I described in the question (building an array of arguments conditionally). By leaving the variables unquoted, who knows what problems you're leaving yourself open to.
– muru
Jan 13 at 15:35
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
@muru You're right, but I still need something like this. I don't quite see how to fix it using the techniques from the other answers. It would be great to see a code fragment done the right way that puts it all together. I'm going to play with Stephane's last option later as that might do what I want.
– Joe
Jan 14 at 10:20
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Like paste.ubuntu.com/26383847?
– muru
Jan 14 at 10:31
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
Just got back to this. Thanks for the example. It makes sense. I'm going to work with it.
– Joe
Mar 9 at 5:11
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f415990%2fhow-can-i-expand-a-quoted-variable-to-nothing-if-its-empty%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I knew I had seen and probably used this before, but it proved difficult to search. Now that Michael showed the syntax, I remembered where I'd first seen it quickly enough: unix.stackexchange.com/a/269549/70524, unix.stackexchange.com/q/68484/70524
– muru
Jan 10 at 7:25
If you know it is some kind of parameter substitution, why didn't you look into the parameter expansion section of the
man
page? (-;– Philippos
Jan 10 at 8:29
1
@Philippos I didn't know what it was at the time, only that I'd seen or used it before. Known knowns and unknown knowns. :(
– muru
Jan 10 at 8:33
1
extra cookie points for mentioning using an array to hold the arguments in the question itself.
– ilkkachu
Jan 10 at 15:12