为什么/ bin / sh与/ bin / bash的行为不同,即使一个指向另一个?

时间:2014-11-03 15:53:20

标签: linux bash shell sh

当我在我的shell中调查this question的答案时,我注意到,即使/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

的内容
#!/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

为什么两个调用的行为不同?

4 个答案:

答案 0 :(得分:79)

bash查看$argv[0]的值(bash在C中实现)以确定如何调用它。

sh调用时,其行为记录为in the manual

  

如果使用名称sh调用Bash,它会尝试模仿启动   sh的历史版本的行为尽可能接近,而   也符合POSIX标准。

     

作为交互式登录shell调用时,或作为非交互式调用   使用-login选项的shell,它首先尝试读取和执行   来自/etc/profile~/.profile的命令,按此顺序排列。该   --noprofile选项可用于禁止此行为。当作为名为sh的交互式shell调用时,Bash会查找该变量   ENV,如果已定义,则展开其值,并使用展开的值   作为要读取和执行的文件的名称。由于shell被调用为sh   不会尝试从任何其他启动读取和执行命令   文件,--rcfile选项无效。非交互式shell   使用名称sh调用不会尝试读取任何其他启动   文件。

     

当调用为sh时,Bash在启动文件后进入POSIX模式   读

bash处于POSIX模式documented here时,有一长串列表(目前有46项)会发生变化。

(POSIX模式可能主要用作测试脚本以便移植到非bash shell的方法。)

顺便说一下,根据调用它们的名称改变行为的程序是相当普遍的。某些版本的grepfgrepegrep是作为单个可执行文件实现的(尽管GNU grep不执行此操作)。 view通常是指向vivim的符号链接;以view调用它会导致以只读模式打开。 Busybox系统包含许多单独的命令,这些命令都是主busybox可执行文件的符号链接。

答案 1 :(得分:20)

调用bash作为sh会导致它在读取正常读取的启动文件后进入 posix模式(而不是POSIX sh会读取的启动文件。)Bash有很多不同的调用模式。您可以从本手册的INVOCATION部分了解这些模式。以下是有关POSIX模式的一些细节。

POSIX模式

此模式意味着bash将在不同程度上尝试符合POSIX期望。正如here所解释的那样,bash对这种模式有几种不同的调用,其含义略有不同:

  1. sh:Bash在读取启动文件后进入POSIX模式。
  2. bash --posix:在读取启动文件之前,Bash进入POSIX模式
  3. set -o posix:Bash切换到POSIX模式。
  4. POSIXLY_CORRECT:如果此变量在bash启动时处于环境中,则shell会在读取启动文件之前进入posix模式,例如bash --posix。如果在bash运行时设置,例如set -o posix

答案 2 :(得分:16)

来自Bash Reference Manual

  

如果使用名称sh调用Bash,它会尝试尽可能接近地模仿sh的历史版本的启动行为,同时也符合POSIX标准。

答案 3 :(得分:10)

因为bash二进制文件会检查它的调用方式(通过argv[0]),如果它以sh运行,则会进入兼容模式。