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

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

为什么这两个调用行为有所不同?

Solutions Collecting From Web of "为什么/ bin / sh与/ bin / bash的行为不同,即使指向另一个也是如此?"

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

其手动调用时的行为记录在手册中 :

如果Bash是以sh的名字被调用的,它会尽可能地模仿sh历史版本的启动行为,同时也符合POSIX标准。

当作为交互式登录shell或具有-login选项的非交互式shell进行调用时,它将首先尝试从/etc/profile~/.profile中按顺序读取和执行命令。 --noprofile选项可以用来抑制这种行为。 当以名称sh作为交互式shell进行调用时,Bash将查找变量ENV ,如果已定义,则展开其值,并使用展开的值作为要读取和执行的文件的名称。 由于作为sh调用的shell不会尝试从任何其他启动文件读取和执行命令,因此--rcfile选项不起作用。 使用名称sh调用的非交互式shell不会尝试读取任何其他启动文件。

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

bash处于POSIX模式时,有一长串的列表(当前有46个条目), 这里记录 。

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

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

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

POSIX模式

这种模式意味着bash将在不同程度上尝试符合POSIX的期望。 正如这里所解释的那样,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

从Bash参考手册 :

如果Bash是以sh的名字被调用的,它会尽可能地模仿sh历史版本的启动行为,同时也符合POSIX标准。

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