当我在外壳中研究这个问题的答案时,我注意到,即使/bin/sh指向/bin/bash系统上的两个命令,它们的行为也有所不同。首先,输出
/bin/sh
/bin/bash
ls -lh /bin/sh
是:
lrwxrwxrwx 1 root root 4 Apr 22 2013 /bin/sh -> bash*
但是,通过以下命令调用以下命令/bin/sh:
/bin/sh -c "script.sh 2> >( grep -v FILTER 2>&1 )"
返回此错误:
/bin/sh: -c: line 0: syntax error near unexpected token '>' /bin/sh: -c: line 0: 'script.sh 2> >( grep -v FILTER 2>&1 )'
通过/bin/bash以下命令运行相同命令时:
/bin/bash -c "script.sh 2> >( grep -v FILTER 2>&1 )"
成功执行,以下是输出:
This should be on stderr
供参考,以下是以下内容script.sh:
script.sh
#!/bin/sh echo "FILTER: This should be filtered out" 1>&2 echo "This should be on stderr" 1>&2 echo "FILTER: This should be filtered out" 1>&2
为什么两个调用的行为不同?
bash查看$argv[0](bash在C语言中实现)的值,以确定如何调用它。
bash
$argv[0]
当作为调用它的行为sh被记录在手册中:
sh
如果使用name调用Bash sh,则它会尝试sh尽可能接近于历史版本的启动行为,同时还要符合POSIX标准。 当作为交互式登录外壳程序或带有该-login选项的非交互式外壳程序调用时,它首先尝试按此顺序从/etc/profile和读取和执行命令~/.profile。该 --noprofile选项可用于禁止此行为。当作为具有名称的交互式shell调用时sh,Bash查找变量ENV,如果定义了变量 ,则扩展其值,并将扩展后的值用作要读取和执行的文件的名称。由于以as身份调用的shell sh 不会尝试从任何其他启动文件读取和执行命令,因此该--rcfile选项无效。使用该名称调用的非交互式外壳程序sh不会尝试读取任何其他启动文件。 当以方式调用时sh,Bash在读取启动文件后进入POSIX模式。
如果使用name调用Bash sh,则它会尝试sh尽可能接近于历史版本的启动行为,同时还要符合POSIX标准。
当作为交互式登录外壳程序或带有该-login选项的非交互式外壳程序调用时,它首先尝试按此顺序从/etc/profile和读取和执行命令~/.profile。该 --noprofile选项可用于禁止此行为。当作为具有名称的交互式shell调用时sh,Bash查找变量ENV,如果定义了变量 ,则扩展其值,并将扩展后的值用作要读取和执行的文件的名称。由于以as身份调用的shell sh 不会尝试从任何其他启动文件读取和执行命令,因此该--rcfile选项无效。使用该名称调用的非交互式外壳程序sh不会尝试读取任何其他启动文件。
-login
/etc/profile
~/.profile
--noprofile
ENV
--rcfile
当以方式调用时sh,Bash在读取启动文件后进入POSIX模式。
bash在POSIX模式下,一长串(目前有46项)更改的内容在此处记录。
(POSIX模式可能最有用,它是测试脚本是否可移植到非bashshell的一种方法。)
顺便说一句,根据调用它们的名称更改其行为的程序是相当普遍的。有些版本grep,fgrep以及egrep作为一个可执行实现(虽然GNU grep并没有这样做)。view通常是指向vi或的符号链接vim;调用它作为view导致以只读模式打开的原因。所述Busybox的系统包括许多与所有符号链接到主各个命令的busybox可执行文件。
grep
fgrep
egrep
view
vi
vim
busybox