/bin/bash-c与直接执行命令有何不同



我很好奇为什么命令:

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

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

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

输出"意外标记'[mydir]'附近的语法错误"

您使用的是双引号,因此父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;'

子命令输出中的不同换行处理。例如,在我的机器上,使用/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中,所以第一个命令行有效(在生成命令行时会去掉换行符),但在第二种情况下则不然——由于"",换行符仍保留在字符串中。使用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

最新更新