The command:
( echo 1 )
works fine when I input it in the command line but if I store it as a variable and call it, it gives the error:
(echo: command not found
Code:
input="( echo 1 )"
$input
Why doesn't it evaluate the parentheses the same way and put it into a subshell when I call it this way?
This is discussed in full detail in BashFAQ #50.
An unquoted expansion goes through only two stages of shell parsing: Field-splitting, and glob expansion. Thus,
( echo 1 )
is first split into fields:(
,echo
,1
, and)
; each is expanded as a glob (moot, as none of them are glob expansions); and then they're run as a command:(
is invoked, with the first argumentecho
, the second argument1
, and the third argument)
.The Right Way to store code is in a function:
...or, if you want to make it more explicit to a human reader that you really want a subshell and weren't using parens rather than braces by error or habit:
...if not possible, one can use
eval
(but be wary of the caveats given in BashFAQ #48):If the real reason you're building a command in a string is to parameterize its contents, use an array instead:
The parentheses are shell syntax.
To reflect syntax which is stored in variable back into the shell for processing, you must use the
eval
command.Merely interpolating the value of the variable into a command line doesn't trigger
eval
evaluation of the syntax. That would be an unwanted intrusion of eval, which would cause all sorts of problems.For instance, consider this:
We just want
somecommand
to be invoked with the character string(parenthesized)
as its argument; we don't want to run a subshell. That sort of implicit eval would turn harmless data into live code, creating a security hole, not to mention a coding nightmare to try to avoid it.The rules for how
$arg
is treated are independent of position; the expansion happens the same way even if$arg
is the first element in the command line:Parameter substitution turns
$arg
into the text(parenthesized)
and then that is tried as a command, not as a shell syntax.To execute the piece of shell script stored in
input
, use:You could also do it like this:
Of course, the subshell approach feeds the code fragment to the same shell which is executing the surrounding script, whereas here we chose the
/bin/sh
which could be different from the invoking shell, or have a different behavior even if it is a symlink to the same shell.