Here is my small bash script snippet.
i=5
command='echo $i'
$command
I want this script to print 5
i.e., I want it to run echo and print 5. But it instead keeps printing $i
. So how do I go about solving this?
Here is my small bash script snippet.
i=5
command='echo $i'
$command
I want this script to print 5
i.e., I want it to run echo and print 5. But it instead keeps printing $i
. So how do I go about solving this?
That would be:
eval "$command"
If you want the content of $command
to be evaluated as shell code.
If you can't guarantee that $command
won't start with -
(which would cause eval
in some shells like bash
to treat it as an option), you may want to run:
eval " $command"
instead. That extra leading space won't affect the way the command is parsed and will prevent $command
from being treated as an option to eval
if it starts with -
. eval -- "$command"
would also work in some shells (including bash
) but is not POSIX (IIRC) and wouldn't work in dash
or the Bourne shell for instance.
Note that your $command
should probably be:
command='echo "$i"'
Unless you did intend $i
to be subject to split+glob
A potentially better way to store code in "variables" would be to use functions:
mycommand() { echo "$i"; }
(using mycommand
instead of command
, as command
is already an existing command).
If $command
is break
/continue
/return
, behaviour will vary depending on the shell.
If you wanted $command
to store a simple command, that is a list of words the first of which is looked up as the command to execute with the list of words as arguments, you'd use an array variable:
command=('echo' '$i' "$i")
"${command[@]}"
That would run echo
, with echo
, $i
and the content of $i
as arguments.
command='echo $i ;x /* '$i
$command
(with the default value of $IFS
) is the one that would make littlest sense. There, $command
would contain a string. The first $i
left as is, the second expanded (as outside the single quotes), and then that string would be subject to split+glob (as $command
is not inside double quotes), the outcome of which would result in a number of words, taken as a simple command again.
eval "$command"
rather than just suggesting to change the quotes to "
, i.e. i=5; command="echo $i"; $command
which also would have worked, you prefer the eval
method? personally I find using bash -c "$command"
to be more reliable - assuming you dont need the command to be executed in current process
– the_velour_fog
Apr 07 '17 at 09:29
command="echo $i"; $command
is not the same thing. That's expanding $i
into the value of $command
and then apply split+glob to $command
. That wouldn't work if $IFS
was modified, that wouldn't work for command='cmd1; cmd2'
, etc. I can't see the point of using bash -c "$command"
unless you do want that command to run in a separate bash
instance. Here that wouldn't work unless you exported $i
.
– Stéphane Chazelas
Apr 07 '17 at 09:34
bash -c "$command"
more reliable than $command
for the reasons you mentioned. the way I would use the commands is bash -c "$command"
when you need to run as a separate instance, e.g. sudo -u $SUDO_USER bash -c "$command"
, eval "$command"
when you want to run in - and affect - the current process .
– the_velour_fog
Apr 07 '17 at 09:56
$command
has the following value: VAR1=foo VAR2=Lo23>-f
, then echo $VAR2
displays Lo23
. Any fix to that?
– payne
Dec 02 '21 at 19:00
>
is a redirection operator in the syntax of the shell, so you'd need it to be quoted if you want it to be part of the string that is assigned to the VAR2
variable: $command
should contain VAR1=foo VAR2='Lo23>-f'
for instance.
– Stéphane Chazelas
Dec 02 '21 at 20:09