在编写shell程序时,我们经常使用/bin/sh和/bin/bash。我通常使用bash,但我不知道它们之间有什么区别。
Bash和sh的主要区别是什么?
用Bash和sh编程时,我们需要注意什么?
在编写shell程序时,我们经常使用/bin/sh和/bin/bash。我通常使用bash,但我不知道它们之间有什么区别。
Bash和sh的主要区别是什么?
用Bash和sh编程时,我们需要注意什么?
当前回答
这个问题经常被提名为试图使用sh的人的典范,他们惊讶于它的行为与bash不同。这里简要介绍了常见的误解和陷阱。
首先,你应该明白会发生什么。
如果您使用sh-scriptname运行脚本,或者使用scriptname运行脚本并使用#/bin/sh在shebang行中,您应该期望POSIX sh行为。如果您使用bashscriptname运行脚本,或者使用scriptname运行脚本并使用#/在shebang行中,您应该期待bash行为。
拥有正确的shebang并通过键入脚本名称(可能带有相对路径或完整路径)来运行脚本通常是首选解决方案。除了正确的shebang之外,这还需要脚本文件具有执行权限(chmod a+x scriptname)。
那么,它们到底有什么不同?
Bash的目标是向后兼容Bourne shell和POSIX,但有许多其他功能。Bash参考手册有一节试图列举差异,但一些常见的混淆来源包括
[[在sh中不可用(只有[[更为笨重和有限)。另请参阅Bash中单方括号和双方括号的区别sh没有数组。一些Bash关键字,如local、source、function、shopt、let、declare和select,不可移植到sh。(一些sh实现支持例如local。)Bash有许多C样式语法扩展,如((i=0;i<=3;i++))循环的三个参数、+=增量赋值等。POSIX暂时接受$'string\nwith\tC\aescapes'特性(这意味着它现在可以在Bash中工作,但在仅遵循当前POSIX规范的系统上,sh尚不支持,而且很可能在未来一段时间内不会支持)。Bash支持<<<“字符串”。Bash有*。{png,jpg}和{0..12}大括号展开。Bash扩展了globbing工具,如用于递归子目录的**(globstar),以及用于使用不同的、更通用的通配符语法的extglob。~仅在Bash中引用$HOME(更一般地,~username指向username的主目录)。这在POSIX中,但在一些POSIX/bin/sh之前的实现中可能缺少。Bash的进程替换为<(cmd)和>(cmd)。Bash有Csh风格的方便重定向别名,如2>&1|和2>&1。。。2>&1Bash支持带有<>重定向的协进程。Bash具有丰富的扩展非标准参数扩展集,如${substring:1:2}、${variable/patter/replacement}、大小写转换等。Bash显著扩展了shell算术的功能(尽管仍然不支持浮点)。有一个过时的遗留$[expression]语法,但应该用POSIX算术$((expression))语法替换。(不过,一些遗留的POSIX前sh实现可能不支持这一点。)一些内置命令具有不可移植的选项,如type-a、printf-v和常年使用的echo-e。像$RANDOM、$SECONDS、$PIPESTATUS[@]和$FUNCNAME这样的神奇变量是Bash扩展。Bash将一些系统设施公开为文件句柄,如/dev/stdin、/dev/fd/<number>、/dev/tcp/<networkaddress>等语法差异,如导出变量=value和[“x”==“y”],它们不可移植(导出变量应与变量赋值分开,[…]中的可移植字符串比较使用单个等号)。许多、许多仅Bash扩展,用于启用或禁用可选行为并公开外壳的内部状态。许多交互使用的便利功能,但不会影响脚本行为。
记住,这是一个简短的列表。请参阅完整铲斗的参考手册,以及http://mywiki.wooledge.org/Bashism许多好的变通办法;和/或尝试http://shellcheck.net/这对许多仅限Bash的功能发出警告。
一个常见的错误是使用#/bin/bashshebang行,但仍然使用shscriptname实际运行脚本。这基本上禁用了任何仅Bash的功能,因此您会遇到语法错误,例如尝试使用数组时。(shebang行在语法上是一个注释,因此在这种情况下它被忽略了。)
不幸的是,当您尝试使用这些构造时,Bash作为sh调用时,它不会发出警告。它也不会完全禁用所有仅Bash的功能,因此通过将其作为sh调用来运行Bash并不是检查脚本是否可正确移植到ash/dash/POSIX sh或类似Heirloom sh的变体的好方法。如果您想检查是否严格遵守POSIX,请尝试posh在其指定的POSIX模式下(但似乎没有适当记录)。
顺便说一句,POSIX标准化工作旨在指定各种类U*x平台行为的行为,包括shell(sh)。然而,这是一个不断发展的文档,因此,一些实现遵循POSIX规范的早期版本;此外,有些遗留实现甚至没有尝试遵守POSIX。最初的Bourne外壳有一些怪癖,后来被POSIX规范纠正了,POSIX规范大部分基于ksh88。(许多Bash扩展也是ksh的创新。)
其他回答
什是什么?
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?
很长一段时间以来,/bin/sh在大多数GNU/Linux系统上都指向/bin/bash。因此,忽略两者之间的差异几乎是安全的。但最近情况开始改变。
/bin/sh不指向/bin/bash的系统的一些常见示例(其中一些系统上甚至不存在/bin/bas)是:
现代Debian和Ubuntu系统,默认将sh符号链接到dash;Busybox,通常在Linux系统启动时作为initramfs的一部分运行。它使用ashshell实现。BSD系统以及一般的任何非Linux系统。OpenBSD使用pdksh,它是KornShell的后代。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标志覆盖符号链接和硬链接,但这种方法的缺点是不可移植-POSIX不需要find来支持-samefile选项,尽管GNU find和FreeBSD find都支持它。
Shebang线
最终,由您决定使用哪一行,将“shebang”行作为脚本的第一行。
E.g.
#!/bin/sh
将使用sh(以及所指向的任何内容),
#!/bin/bash
将使用/bin/bash(如果不可用,则会失败并显示错误消息)。当然,您也可以指定其他实现,例如。
#!/bin/dash
使用哪一个
对于我自己的脚本,我更喜欢sh,原因如下:
它是标准化的它更简单易学它在POSIX系统中是可移植的——即使它们碰巧没有bash,也需要有sh
使用bash也有好处。它的特性使编程更加方便,与其他现代编程语言的编程类似。其中包括作用域局部变量和数组。Plain sh是一种非常简约的编程语言。
UNIX.COM发布
外壳功能
下表列出了我认为可以让您选择一个外壳而不是另一个外壳的大多数功能。它不是一个明确的列表,也不包括每个可能的外壳的每个可能的特性。只有在操作系统附带的版本中,或者在直接从标准发行版编译的情况下,功能才被视为在shell中。特别是下面指定的C shell是SUNOS4.*上提供的,现在有相当多的供应商提供了tcsh或他们自己的增强型C shell(他们并不总是明显地表明他们正在提供tcsh)。
代码:
sh csh ksh bash tcsh zsh rc es
Job control N Y Y Y Y Y N N
Aliases N Y Y Y Y Y N N
Shell functions Y(1) N Y Y N Y Y Y
"Sensible" Input/Output redirection Y N Y Y N Y Y Y
Directory stack N Y Y Y Y Y F F
Command history N Y Y Y Y Y L L
Command line editing N N Y Y Y Y L L
Vi Command line editing N N Y Y Y(3) Y L L
Emacs Command line editing N N Y Y Y Y L L
Rebindable Command line editing N N N Y Y Y L L
User name look up N Y Y Y Y Y L L
Login/Logout watching N N N N Y Y F F
Filename completion N Y(1) Y Y Y Y L L
Username completion N Y(2) Y Y Y Y L L
Hostname completion N Y(2) Y Y Y Y L L
History completion N N N Y Y Y L L
Fully programmable Completion N N N N Y Y N N
Mh Mailbox completion N N N N(4) N(6) N(6) N N
Co Processes N N Y N N Y N N
Builtin artithmetic evaluation N Y Y Y Y Y N N
Can follow symbolic links invisibly N N Y Y Y Y N N
Periodic command execution N N N N Y Y N N
Custom Prompt (easily) N N Y Y Y Y Y Y
Sun Keyboard Hack N N N N N Y N N
Spelling Correction N N N N Y Y N N
Process Substitution N N N Y(2) N Y Y Y
Underlying Syntax sh csh sh sh csh sh rc rc
Freely Available N N N(5) Y Y Y Y Y
Checks Mailbox N Y Y Y Y Y F F
Tty Sanity Checking N N N N Y Y N N
Can cope with large argument lists Y N Y Y Y Y Y Y
Has non-interactive startup file N Y Y(7) Y(7) Y Y N N
Has non-login startup file N Y Y(7) Y Y Y N N
Can avoid user startup files N Y N Y N Y Y Y
Can specify startup file N N Y Y N N N N
Low level command redefinition N N N N N N N Y
Has anonymous functions N N N N N N Y Y
List Variables N Y Y N Y Y Y Y
Full signal trap handling Y N Y Y N Y Y Y
File no clobber ability N Y Y Y Y Y N F
Local variables N N Y Y N Y Y Y
Lexically scoped variables N N N N N N N Y
Exceptions N N N N N N N Y
上表的键。
Y功能可以使用此外壳完成。
外壳中不存在N功能。
F功能只能通过使用shell函数完成机械装置
L读线库必须链接到shell中才能启用此功能。
上表注释
此功能在原始版本中不存在,但现在已成为几乎是标准的。这一功能是相当新的,因此通常在许多版本的外壳,它正在逐渐进入标准分布。许多人认为这种外壳的Vi仿真是不完整。此功能不是标准功能,但存在非官方补丁执行此操作。名为“pdksh”的版本是免费提供的,但没有AT&T版本的全部功能。这可以通过外壳可编程完成机制完成。仅通过ENV环境变量指定文件。
什:http://man.cx/sh 猛击:http://man.cx/bash
TL;DR:Bash是sh的超集,具有更优雅的语法和更多的功能。在几乎所有情况下使用Bash-shebang线路都是安全的,因为它在现代平台上非常普遍。
注意:在某些环境中,sh就是Bash。检查sh--版本。
Linux操作系统提供了不同类型的shell。尽管shell有许多共同的命令,但每种类型都有独特的特性。让我们研究不同种类的常用贝壳。
Sh外壳:
Sh外壳也称为伯恩外壳。Shshell是1977年美国电话电报公司贝尔实验室斯蒂芬·伯恩为Unix计算机开发的第一个shell。它包括许多脚本工具。
Bash外壳:
Bash shell代表Bourne Again shell。Bash shell是大多数Linux发行版中的默认shell,并替代Sh shell(Sh shell也将在Bash shell中运行)。Bashshell可以执行绝大多数Shshell脚本而无需修改,并提供命令行编辑功能。
它们几乎相同,但bash有更多的功能——sh(或多或少)是bash的一个子集。
sh通常意味着最初的Bourne shell,它早于bash(Bourne*再次*shell),创建于1977年。但是,在实践中,最好将其视为符合1992年POSIX标准的高度交叉兼容的外壳。
以#!开头的脚本/bin/sh或使用shshell通常是为了向后兼容。任何unix/linux操作系统都会有一个sh shell。在Ubuntu上,sh经常调用dash,而在MacOS上,它是一个特殊的POSIX版本的bash。这些外壳可能是符合标准的行为、速度或向后兼容性的首选。
bash比原来的sh更新,增加了更多的功能,并寻求与sh向后兼容。sh程序通常在bash中运行得很好。bash在几乎所有linux/unix机器上都可用,并且通常在默认情况下使用,但值得注意的是,自Catalina(10.15)起,MacOS默认为zsh。默认情况下,FreeBSD没有安装bash。