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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26717870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:41:30  来源:igfitidea点击:

Why does /bin/sh behave differently to /bin/bash even if one points to the other?

linuxbashshellsh

提问by Squirrel

While I was playing around in my shell investigating the answer to this question, I noticed that, even though /bin/shwas pointing to /bin/bashon my system, the two commands behave differently. First of all, the output of

当我在 shell 中研究这个问题的答案时,我注意到,即使/bin/sh指向/bin/bash我的系统,这两个命令的行为也不同。首先,输出

ls -lh /bin/sh

is:

是:

lrwxrwxrwx 1 root root 4 Apr 22  2013 /bin/sh -> bash*

However, invoking the following command through /bin/sh:

但是,通过调用以下命令/bin/sh

/bin/sh -c "script.sh 2> >( grep -v FILTER 2>&1 )"

returns this error:

返回此错误:

/bin/sh: -c: line 0: syntax error near unexpected token '>'
/bin/sh: -c: line 0: 'script.sh 2> >( grep -v FILTER 2>&1 )'

While running the same command through /bin/bash:

通过/bin/bash以下方式运行相同的命令时:

/bin/bash -c "script.sh 2> >( grep -v FILTER 2>&1 )"

executes successfully, here is the output:

执行成功,输出如下:

This should be on stderr

For reference, here is the contents of 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

Why do the two invocations behave differently?

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

回答by Keith Thompson

bashlooks at the value of $argv[0](bash is implemented in C) to determine how it was invoked.

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

Its behavior when invoked as shis documented in the manual:

当作为调用它的行为sh被记录在手册中

If Bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of shas closely as possible, while conforming to the POSIX standard as well.

When invoked as an interactive login shell, or as a non-interactive shell with the -loginoption, it first attempts to read and execute commands from /etc/profileand ~/.profile, in that order. The --noprofileoption may be used to inhibit this behavior. When invoked as an interactive shell with the name sh, Bash looks for the variable ENV, expands its value if it is defined, and uses the expanded value as the name of a file to read and execute. Since a shell invoked as shdoes not attempt to read and execute commands from any other startup files, the --rcfileoption has no effect. A non-interactive shell invoked with the name shdoes not attempt to read any other startup files.

When invoked as sh, Bash enters POSIX mode after the startup files are read

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

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

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

There's a long list (currently 46 items) of things that change when bashis in POSIX mode, documented here.

有很长的列表(目前有 46 项)bash在 POSIX 模式下会发生变化,记录在这里

(POSIX mode is probably useful mostly as a way to test scripts for portability to non-bashshells.)

(POSIX 模式可能主要用作测试脚本对非bashshell 的可移植性的一种方式。)

Incidentally, programs that change their behavior depending on the name under which they were invoked are fairly common. Some versions of grep, fgrep, and egrepare implemented as a single executable (though GNU grepdoesn't do this). viewis typically a symbolic link to vior vim; invoking it as viewcauses to open in read-only mode. The Busyboxsystem includes a number of individual commands that are all symlinks to the master busyboxexecutable.

顺便说一下,根据调用它们的名称来改变其行为的程序是相当普遍的。有些版本grepfgrep以及egrep作为一个可执行实现(虽然GNUgrep并没有这样做)。view通常是指向vi或的符号链接vim;调用它view会导致以只读模式打开。所述Busybox的系统包括许多与所有符号链接到主各个命令的busybox可执行文件。

回答by kojiro

Invoking bash as shcauses it to enter posix modeafter reading the startup files it would normally read (as opposed to the startup files a POSIX sh would read.) Bash has many different invocation modes. You can find out about these modes from the INVOCATIONsection of the manual. Here is some detail about the POSIX mode.

调用 bash assh会导致它在读取它通常读取的启动文件后进入posix 模式(与 POSIX sh 将读取的启动文件相反)。Bash 有许多不同的调用模式。您可以从INVOCATION手册部分了解这些模式。以下是有关 POSIX 模式的一些详细信息。

POSIX mode

POSIX 模式

This mode means bash will try, in various degrees, to conform to POSIX expectations. As explained here, bash has a few different invocations for this mode, with slightly different implications:

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

  1. sh: Bash enters POSIX mode after reading startup files.
  2. bash --posix: Bash enters POSIX mode beforereading startup files.
  3. set -o posix: Bash switches to POSIX mode.
  4. POSIXLY_CORRECT: If this variable is in the environment when bash starts, the shell enters posix mode beforereading the startup files, like bash --posix. If it is set while bash is running, like set -o posix.
  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.

回答by Etan Reisner

From the Bash Reference Manual:

来自Bash 参考手册

If Bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well.

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

回答by Carl Norum

Because the bashbinary checks how it was invoked (via argv[0]) and enters a compatibility mode if it's being run as sh.

因为bash二进制文件会检查它是如何被调用的(通过argv[0]),如果它作为sh.