在编写 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