That's because the variable is expanded after the pipes and redirection is already done. So in that case |
is just another argument to echo
, not a pipe that's interpreted by the shell.
Recommended reading: http://mywiki.wooledge.org/BashFAQ/050
When executing the command
echo hello man | awk '{print $1}'
the shell will see the |
and setup a pipeline, on one side it will run the command echo hello man
and on the other awk '{print $1}'
. The commands then get subjected to word splitting so you run the command echo
with 2 arguments: hello
and man
. On the other side you run the command awk
with a single argument (because of the quoting) "{print $1}"
When that command is stored as a string though the shell first looks at the command $y
and sees no redirection to do. It then expands $y
and then does word splitting on it. It gets expanded to the same looking string, but now it's too late for redirection. So it gets split into the words echo
, hello
, man
, |
, awk
, "{print
, $1}"
(note that the argument to awk
now gets split because the quotes inside the string are part of the string, not syntactical)
The first word in that list is echo
so that's the command, and all the rest of the words are passed as arguments to it, which is why you see the output
hello man | awk "{print $1}"
When you do the eval
line, it takes that same string and tells bash
to parse it as though it had been typed so the pipe once again becomes syntatical and causes the pipeline.
Because echo
puts its arguments on the same line it's a little tougher sometimes to see what's happening, if we replace it with printf '%s
'
each argument will become its own line though:
$ y='printf %s
hello man | awk "{print $1}"'
$ $y
hello
man
|
awk
"{print
$1}"
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…