bash4.3 # pwd
/bin
bash4.3 # ll sh
lrwxrwxrwx. 1 root root 4 May 17 22:22 sh -> bash
bash4.3 # ll bash
-rwxr-xr-x. 1 root root 1072056 May 17 22:22 bash
bash4.3 # bash
bash4.3 # sh
sh-4.3#
我的操作系统是 fedora 24(默认 GNOME 版本)。
从例子中我们可以知道: 下的/bin
是bash
二进制可执行文件;sh
是 的软链接bash
。
因此,据我所知,type bash and press enter
应该产生与完全相同的结果type sh and press enter
。
当我 时type bash and press enter
,我得到了[root@localhost bin]#
预期的结果。
然而,如果我type sh and press enter
,我惊讶地得到了sh-4.3#
。
原因何在?
答案1
这是一个有记录的特征。
如果您通过名为的符号链接运行 bash sh
,bash 将以sh
兼容模式启动。
从man bash
:
如果使用名称 sh 调用 bash,它会尝试尽可能地模仿 sh 的历史版本的启动行为,同时符合 POSIX 标准。当作为交互式登录 shell 或使用 --login 选项的非交互式 shell 调用时,它首先尝试按顺序从 /etc/profile 和 ~/.profile 读取并执行命令。可以使用 --noprofile 选项来禁止此行为。当使用名称 sh 调用作为交互式 shell 时,bash 会查找变量 ENV,如果已定义则扩展其值,并使用扩展的值作为要读取和执行的文件的名称。由于作为 sh 调用的 shell 不会尝试从任何其他启动文件中读取和执行命令,因此 --rcfile 选项无效。使用名称 sh 调用的非交互式 shell 不会尝试读取任何其他启动文件。当作为 sh 调用时,bash 在读取启动文件后进入 posix 模式。
程序如何知道使用什么名称来启动它?
如果是 c 程序,它可以检查argv[0]
。如果是 shell 或 perl 脚本,它可以检查$0
。
作为示例,让我们考虑这个简单的 shell 脚本:
$ cat utc
#!/bin/sh
case "${0##*/}" in
utc) date -u ;;
et) TZ=US/Eastern date ;;
esac
$0
是调用该脚本的名称。 ${0##*/}
是调用该脚本后删除所有目录名的名称。
让我们创建这个符号链接:
ln -s utc et
因此,utc
和et
都运行相同的可执行文件,但它们提供不同的结果。当以 运行时utc
,它会输出世界时。当以 运行时et
,它会输出美国东部时间。例如:
$ utc
Wed Jul 20 18:14:18 UTC 2016
$ et
Wed Jul 20 14:14:20 EDT 2016