If I run this:

echo "echo 'a'; echo 'b'"

It produces a string which I can then run, and it works - echoes a\nb\n.

However, this does not work:

$(echo "echo 'a'; echo 'b'")

Why not? It doesn't work for any command, not just echo. How do I execute a string containing two or more commands?

  • I don't understand the question. eval $(echo "echo 'a'; echo 'b'") works without problems. It is in general not a good idea to talk about problems instead of giving the exact error message(s). May 16 '14 at 12:54

In $(echo "echo 'a'; echo 'b'"), the shell sees a command substitution. And that's it. So that's going to be a simple command whose arguments are the resulting of the split+glob operator upon the expansion of the command substitution.

The shell will take the output of the echo "echo 'a'; echo 'b'" command, in this case echo 'a'; echo 'b'\n, remove the trailing newline characters so that becomes echo 'a'; echo 'b', split that according the value of the $IFS variable.

If $IFS has not been changed from its default, that will be 4 words: echo, 'a';, echo and 'b'. Each of those words will be subject to globbing. Here, none contain globbing characters, so those words will stay as they are.

So we've got 4 arguments to run a simple command. The first argument will be used to derive the command to run. echo is built-in most shells. So the shell will call its echo builtin with those 4 arguments.

echo ignores its first (0th) argument and outputs the other ones separated by space characters and terminated by a newline character. Some echo implementations expand backslash escape sequences, but there's none here. So echo will output:

'a'; echo 'b'\n

If you want to eval it, that is if you want to have that string interpreted as shell code, use eval:

eval "echo 'a'; echo 'b'"

That's also recognised as a simple command. Because of the quotes, the shell sees two "words": eval and echo 'a'; echo 'b'. Again, those will make up the arguments to the command that is derived from the first.

Here the command is the shell's eval builtin command. Again, eval ignores its first agument. What it does is concatenate its other arguments (here there's only one) with spaces and interpret the resulting string as shell code. When interpreting

echo 'a'; echo 'b'

The shell sees an unquoted ; which delimits commands. The first one is treated as a simple command which ends up calling echo with two arguments... etc.

if eval "( service networking restart &> /dev/null   &&   ping -c3 google.com &> /dev/null )"; then      
   echo "service is running"                              
   echo "service is not running"    
  • 2
    You don't seem to actually need the eval in your example.
    – Kusalananda
    May 16 '19 at 6:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.