0

bash has token substitution, either via the $() syntax or via the `` syntax, eg:

$ $(echo "echo hi")
hi

AFAIK, that works like so:

  • first evaluate the inner command: echo "echo hi", which outputs echo hi
  • then execute the resulting string as a command echo hi, which produces hi

That being the case, I would have expected the following to write hi to file /tmp/hi

$ $(echo "echo hi > /tmp/hi")

but instead, it writes nothing to any file, and outputs:

hi > /tmp/hi

What's going on here? I originally thought it might be because there are spaces in the string, but the following disconfirms that theory:

$ $(echo "echo hi bob")
hi bob
2

The part of bash's manual which applies to your case is this:

SIMPLE COMMAND EXPANSION

When a simple command is executed, the shell performs the following expansions, assignments, and redirections, from left to right.

  1. The words that the parser has marked as variable assignments (those preceding the command name) and redirections are saved for later processing.

  2. The words that are not variable assignments or redirections are expanded. If any words remain after expansion, the first word is taken to be the name of the command and the remaining words are the arguments.

  3. Redirections are performed as described above under REDIRECTION.

  4. The text after the = in each variable assignment undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal before being assigned to the variable.

Your $(echo "echo hi > /tmp/hi") command substitution will be expanded at point 2, and since the > redirection couldn't have been marked for later processing at point 1 (since it only appeared as the result of the command substitution), it will not be performed as per point 3.

If the redirections weren't pre-processed before the expansions, then something like

to='>'; echo foo $to bar

will echo foo into the file bar, instead of just echoing foo > bar as it does.

Notice that bash is different from other shells in the fact that it's also performing split + globbing on the word following a redirection operator (and die with "ambiguous redirect" if it expands to multiple words). For instance, this

var='a b'; echo > $var

will error out in bash instead of clobbering a file named a b (as do other shells).

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.