Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run a shell command from a variable in a shell script

I am trying to run a command from a variable in shell script. The shell being used is bash shell.

The file exp contains:

abcdef

Executing the following command:

sed s/b/\ / exp

...produces the output:

a  cdef

But executing:

cmd="sed s/b/\ / exp"
echo $cmd
$cmd

...produces the following error:

sed s/b/\ / exp
sed: -e expression #1, char 5: unterminated `s' command

I can see that adding eval in front of the execution works. But I cannot understand why. Can you explain why one method is working and the other is not working?

like image 833
Yosha Avatar asked Feb 18 '15 09:02

Yosha


People also ask

How do you run a command in a variable in shell script?

Here, the first line of the script i.e. “#!/bin/bash” shows that this file is in fact a Bash file. Then we have created a variable named “test” and have assigned it the value “$(echo “Hi there!”)”. Whenever you want to store the command in a variable, you have to type that command preceded by a “$” symbol.

How do you pass the output of a command to a variable in a shell script?

To store the output of a command in a variable, you can use the shell command substitution feature in the forms below: variable_name=$(command) variable_name=$(command [option ...] arg1 arg2 ...) OR variable_name='command' variable_name='command [option ...]


3 Answers

The problem you are having is that the space itself is not being interpreted properly by Bash.

See how it works well if you replace the b with another character, say X:

$ cmd="sed s/b/X/ exp"
$ $cmd
aXcdef

So the workaround is to use the hexadecimal for the space, which is 20:

$ cmd="sed s/b/\x20/ exp"
$ $cmd
a cdef

Or to use eval to execute the command itself:

$ cmd="sed s/b/\ / exp"
$ eval "$cmd"
a cdef

As Tom Fenech suggested, storing commands in variables in not a good approach, as described in I'm trying to put a command in a variable, but the complex cases always fail!. It can work sometimes but in other cases can produce unpredictable results. An alternative is to consider using a function.

Finally, note eval can come handy in cases like this, only that being very careful on what is stored. Some good reading: Variable as command; eval vs bash -c.

like image 183
fedorqui 'SO stop harming' Avatar answered Oct 07 '22 05:10

fedorqui 'SO stop harming'


It looks like a quoting issue:

cmd="sed s/b/\ / exp" makes $cmd hold a sequence of characters with no special meaning. So your \ does not escape your space.

eval treats that sequence of characters as a command, and re-assign the special meaning to your \.

See also: Preserving quotes in bash function parameters

like image 31
Chen Levy Avatar answered Oct 07 '22 06:10

Chen Levy


If you need the output in the variable then use,

cmd=$(sed 's/b/ /' exp)

Like @thomas says, If you are using the variable you can use the double quotes.

like image 1
Karthikeyan.R.S Avatar answered Oct 07 '22 06:10

Karthikeyan.R.S