/ bin / bash -c与直接执行命令有什么不同?

时间:2014-10-02 19:06:15

标签: bash

我很好奇为什么命令:

for f in `/bin/ls /mydir | sort | tail -n 10`; do echo $f; done;

输出/ dir中的最后十个文件,但

/bin/bash -c "for f in `/bin/ls /mydir | sort | tail -n 10`; do echo $f; done;"

在意外令牌附近输出"语法错误' [/ mydir中的文件]'"

2 个答案:

答案 0 :(得分:5)

您正在使用双引号,因此父shell在将参数传递给/bin/bash之前插入反引号和变量。

因此,您的/bin/bash收到以下参数:

-c "for f in x
y
z
...
; do echo ; done;"

这是语法错误。

要避免这种情况,请使用单引号传递您的参数:

/bin/bash -c 'for f in `/bin/ls /mydir | sort | tail -n 10`; do echo $f; done;'

答案 1 :(得分:2)

子命令输出中的不同换行处理。例如,在我的机器上,使用/bin我得到了第一个例子的输出:

rmdir
sh
sleep
stty
sync
tcsh
test
unlink
wait4path
zsh

但后者:

/bin/bash: -c: line 1: syntax error near unexpected token `sh'
/bin/bash: -c: line 1: `sh'

因为在两种情况下命令替换都发生在你的第一个 shell中,你的第一个命令就会起作用(在创建命令行时会删除换行符),但在第二种情况下它并没有&#39 ; t - 由于你的"",它们仍保留在字符串中。使用echo而不是bash -c可以展示这一点:

$ echo "for f in `/bin/ls /bin | sort | tail -n 10`; do echo \$f; done"
for f in rmdir
sh
sleep
stty
sync
tcsh
test
unlink
wait4path
zsh; do echo $f; done

您可以从中看到bash -c看到的内容及其无效的原因 - sh位于do之前!

您可以使用单引号,但这会导致子命令在新的子shell中运行:

$ /bin/bash -c 'for f in `/bin/ls /bin | sort | tail -n 10`; do echo $f; done'
rmdir
sh
sleep
stty
sync
tcsh
test
unlink
wait4path
zsh

如果不行,你需要摆脱这些换行符:

$ /bin/bash -c "for f in `/bin/ls /bin | sort | tail -n 10 | tr '\n' ' '`; do echo \$f; done"
rmdir
sh
sleep
stty
sync
tcsh
test
unlink
wait4path
zsh