2014-10-02 1464 views
4

我很好奇,为什么条命令:/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文件]'”

回答

5

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

因此,你的/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;' 
+0

一次偶然的机会,这样的回答帮我解决一个奇怪的错误(部署/ Capistrano的/作曲/等),根本原因:双引号VS 。在一个命令中的单引号自动拼接在一起。谢谢。 – Wolfram 2015-01-26 11:24:09

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' 

因为命令替换发生在你的第一壳在这两个例如,你的第一个作品(在制作命令行时删除了换行符),但在第二种情况下它不会 - 由于你的"",它们仍保留在字符串中。使用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