问:
在编写 shell 程序时,我们经常使用 /bin/sh 和 /bin/bash。我通常使用 bash,但我不知道它们之间有什么区别。
Bash 和 sh 之间的主要区别是什么 ?
在使用 Bash 和 sh 编程时,我们需要注意什么 ?
答:
什么是 sh?
sh(或 Shell 命令语言) 是一种由 POSIX 标准描述的编程语言。它有很多实现 (ksh88, Dash,…)。Bash 也可以被认为是 sh 的一种实现 (见下文)。
因为 sh 是一个规范,而不是实现,所以 /bin/sh 在大多数 POSIX 系统上是指向实际实现的符号链接 (或硬链接)。
Bash 是什么 ?
Bash 最初是一个 sh 兼容的实现 (尽管它比 POSIX 标准早了几年),但随着时间的推移,它获得了许多扩展。这些扩展中的许多可能会改变有效的 POSIX shell 脚本的行为,因此 Bash 本身并不是有效的 POSIX shell。相反,它是 POSIX shell 语言的一种方言。
Bash 支持——posix 开关,这使它更符合 posix。如果以 sh 方式调用,它还会尝试模仿 POSIX。
sh = bash?
很长一段时间以来,在大多数 GNU/Linux 系统中,/bin/sh 指向 /bin/bash。因此,忽略两者之间的差异几乎是安全的。但这种情况最近开始发生变化。
在一些常见的系统中,/bin/sh 并不指向 /bin/bash(在某些情况下,/bin/bash 甚至可能不存在):
1. 现代的 Debian 和 Ubuntu 系统,默认将 sh 符号链接到 dash;
2. Busybox,通常在 Linux 系统启动期间作为 initramfs 的一部分运行。它使用 ash shell 实现。
3. BSD 系统,以及一般任何非 linux 系统。OpenBSD 使用的 pdksh 是 KornShell 的后代。FreeBSD 的 sh 是最初的 Unix Bourne shell 的后代。Solaris 有自己的 sh,但很长一段时间都不兼容 posix; 可以从 heiloom 项目中获得免费的实现。
如何知道系统中的 /bin/sh 指向什么 ?
复杂的是 /bin/sh 可能是符号链接或硬链接。如果它是一个符号链接,一种可移植的解决方法是 :
% file -h /bin/sh
/bin/sh: symbolic link to bash
如果是硬链接,试试
% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash
事实上,-L 标志涵盖了符号链接和硬链接,但这种方法的缺点是它是不可移植的- POSIX 不需要 find 来支持 -samefile 选项,尽管 GNU find 和 FreeBSD find 都支持它。
Shebang 行
最终,通过将 «shebang» 行作为脚本的第一行,你来决定使用哪一个。
如:
#!/bin/sh
将使用 sh(以及它指向的任何内容),
#!/bin/bash
如果有 /bin/bash,将使用它 (如果没有,则失败并报错)。当然,你也可以指定另一种实现,例如 :
#!/bin/dash
PS:
本文首发于公众号: 程序熵, 更多精彩文章请点击关注 code-shang