在编写 shell 程序时,我们经常使用/bin/sh
和/bin/bash
。我通常使用bash
,但我不知道它们之间有什么区别。
bash
和sh
之间的主要区别是什么?
在使用bash
和sh
编程时我们需要注意什么?
sh
(或 Shell 命令语言)是POSIX 标准描述的编程语言。它有很多实现( ksh88
, dash
,...)。 bash
也可以被认为是sh
的实现(见下文)。
因为sh
是规范而不是实现,所以/bin/sh
是大多数 POSIX 系统上实际实现的符号链接(或硬链接)。
bash
最初是一个与sh
兼容的实现(虽然它早于 POSIX 标准几年),但随着时间的推移,它已经获得了许多扩展。其中许多扩展可能会改变有效 POSIX shell 脚本的行为,因此bash
本身并不是一个有效的 POSIX shell。相反,它是 POSIX shell 语言的方言。
bash
支持--posix
开关,这使它更符合 POSIX 标准。如果调用sh
它也会尝试模仿 POSIX。
很长一段时间, /bin/sh
曾经指向大多数 GNU / Linux 系统上的/bin/bash
。结果,忽略两者之间的差异几乎是安全的。但最近这种情况开始发生变化。
/bin/sh
未指向/bin/bash
(以及其中某些/bin/bash
甚至可能不存在)的系统的一些常见示例是:
sh
到dash
默认; initramfs
一部分运行。它使用ash
shell 实现。 pdksh
。 FreeBSD 的sh
是原始 UNIX Bourne shell 的后代。 Solaris 有自己的sh
,很长一段时间不符合 POSIX 标准; Heirloom 项目提供免费实施。 你怎么能找到你的系统上/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
标志包括符号链接和硬链接,但这种方法的缺点是它不可移植 - 虽然GNU find和FreeBSD 都支持它,但 POSIX 不需要 find
来支持-samefile
选项。
最终,由你来决定使用哪一个,通过编写 «shebang» 系列。
例如
#!/bin/sh
将使用sh
(以及任何恰好指向的东西),
#!/bin/bash
如果它可用,将使用/bin/bash
如果不可用则失败,并显示错误消息)。当然,您也可以指定其他实现,例如
#!/bin/dash
对于我自己的脚本,我更喜欢sh
,原因如下:
bash
,它们也需要sh
使用bash
也有好处。它的特点使编程更方便,类似于其他现代编程语言的编程。这些包括范围局部变量和数组。 Plain sh
是一种非常简约的编程语言。
sh
: http : //man.cx/sh
bash
: http : //man.cx/bash
TL; DR : bash
是sh
的超集,具有更优雅的语法和更多功能。在几乎所有情况下使用 bash shebang 系列是安全的,因为它在现代平台上非常普遍。
注意:在某些环境中, sh
是 bash
。检查sh --version
。
这个问题经常被提名为试图使用sh
人的规范,并且惊讶于它的行为与bash
。以下是常见误解和陷阱的快速概述。
首先,您应该了解会发生什么。
sh scriptname
运行脚本,或者使用scriptname
运行脚本并在shebang行中使用#!/bin/sh
,则应该期望 POSIX sh
行为。 bash scriptname
运行脚本,或者使用scriptname
运行它并且在 shebang 行中有#!/bin/bash
(或本地等效项),那么您应该期望 Bash 行为。 拥有正确的 shebang 并通过仅键入脚本名称(可能具有相对路径或完整路径)来运行脚本通常是首选解决方案。除了正确的 shebang 之外,这还要求脚本文件具有执行权限( chmod a+x scriptname
)。
那么,它们实际上有何区别?
Bash 参考手册有一个部分试图列举差异,但一些常见的混淆来源包括
[[
不适用于sh
(仅限于[
更笨重且有限])。 sh
没有数组。 local
, source
, function
和select
不可移植到sh
。 (有些sh
实现支持例如local
。) $'string\nwith\tC\aescapes'
和for((i=0;i<=3;i++))
循环, +=
增量赋值等的三参数。 <<<'here strings'
。 *.{png,jpg}
和{0..12}
支撑扩展。 ~
仅在 Bash 中引用$HOME
(更常见的是~username
名主目录的username
)。 /bin/sh
实现中产生。 <(cmd)
和>(cmd)
。 &|
为2>&1 |
和&>
for > ... 2>&1
<>
重定向支持协处理。 ${substring:1:2}
, ${variable/pattern/replacement}
,case 转换等。 请记住,这是一个简略的列表。有关完整的独家新闻,请参阅参考手册; 有关很多良好的解决方法,请参阅http://mywiki.wooledge.org/Bashism ; 和 / 或尝试http://shellcheck.net/警告许多 Bash 功能。
一个常见的错误是有一个#!/bin/bash
shebang 行,但是然后使用sh scriptname
来实际运行脚本。这基本上禁用了任何仅限 Bash 的功能,因此您会遇到语法错误,例如尝试使用数组。
不幸的是,当你尝试使用这些结构作为sh
时,Bash 不会发出警告。它不完全禁用所有猛砸唯一的功能,要么,所以通过调用它运行 bash 作为sh
不检查,如果你的脚本是正确移植到一个好办法ash
/ dash
/ POSIX sh
或类似变种传家宝sh