sh与bash的区别
结论:对于一般开发者,没有区别;对于要使脚本兼容较老系统,或者兼容其他shell(如ksh,dash),那么意义可能很重大,要确保自己代码没有bash扩展的特性。
区别
sh是早期版本,用POSIX标准,没有bash扩展的特性;bash是后期版本,有bash扩展的特性(默认模式、bash标准模式)。
bash扩展的特性
- 数组支持
[[
条件测试,提供了比[
(POSIXtest
命令) 更强大的条件测试结构,支持模式匹配、逻辑运算等。function
关键字:Bash 允许使用function
关键字定义函数。local
关键字:可以在函数中定义局部变量,而 POSIX shell 不支持此特性。- 进程替换:支持使用
<(command)
或>(command)
进行进程替换。 shopt
命令:Bash 允许通过shopt
来开启或关闭 shell 的某些特性。- 扩展的重定向:支持
|&
语法将标准输出和标准错误重定向到同一管道。 **
递归通配符:支持使用**
来递归匹配文件和目录。- 字符串操作:Bash 提供了丰富的字符串处理功能,例如
${var#pattern}
、${var/pattern/replacement}
等。 $RANDOM
和$PPID
等特殊变量:这些变量是 Bash 特有的,用于生成随机数、获取父进程 ID 等。- 内置算术表达式:支持
(( ))
进行算术运算,比expr
更灵活。 - Here字符串 (
<<<
):将字符串作为输入传递给命令。 - 命令历史扩展:Bash 提供强大的命令历史记录功能,例如
!!
重复上一个命令,!n
执行第 n 个命令。 - 别名(alias)支持:Bash 支持通过
alias
定义命令的别名。 - 数组切片:Bash 提供数组的切片操作,用来获取数组的部分元素。
据(这篇文章)说,POSIX模式下,shell遇到错误会停止;默认模式shell遇到错误仍然进行;(这里说的错误是指运行时的返回的非0值,而不是指脚本中的语法错误。)
然而,这个说法是有问题的。
理论上,POSIX模式下,不支持bash扩展特性,实际上不是。
确定sh或bash的真实指向
以sh为例
- 确定sh的真实路径,
which sh
,一般是/usr/bin/sh
- 查看sh的指向,
ll /usr/bin/sh
,得到lrwxrwxrwx. ........ /usr/bin/sh -> bash
。这里看到lrwx..... ->bash
,所以/usr/bin/sh
是一个软链接,指向bash。
尽管sh指向bash,但通过sh执行脚本,仍然会启用POSIX模式。
脚本解释器(sh或bash)的优先级
执行脚本的命令sh 或 bash
>优先于
脚本头定义的【shebang】 >优先于
系统默认的shell。
若,通过sh 或 bash调用脚本,解释器为sh 或 bash;
若,通过相对路径、绝对路径调用脚本,解释器由脚本头的【shebang】决定;
若,通过路径调用脚本,脚本头也没有【shebang】,则由系统默认的shell决定;
结论:区别不大,对于普通开发者来说
- 不论是不是POSIX模式,不论脚本头如何写(
#!/bin/sh或 #!/bin/bash
),不论用sh 或 bash 或 路径调用法
,不论加不加--posix参数
脚本中的数组与[[]]
都支持。即,bash扩展特性都支持。 - shell遇到错误是否继续执行,与POSIX模式无关,但与
set -e
选项有关,默认set -e是关闭的
,遇到错误仍然继续。这里的错误,是指脚本运行时抛出的非0返回值,而不是指脚本中的语法错误,语法错误都会造成脚本停止。 - 可以通过
if [ -o posix ]
来区分POSIX模式,但在bash扩展特性都支持的情况下,没有太大意义;
为什么?
chatgpt给出的原因是,POSIX模式(POSIX兼容模式)与POSIX标准不一样,POSIX兼容模式会让bash尽量符合POSIX标准,但不会完全禁用所有的bash扩展。
区分还有意义吗?
有。当你需要编写一个兼容老系统的脚本,或者要在其他非bash的shell(ksh,dash)上运行的脚本,需要注意不要有bash扩展特性。
其他:执行shell的5种方式
参考
- 绝对路径、相对路径法,
./test.sh
- sh、bash法,
sh test.sh
- source或【.】法,
source test.sh 或 . test.sh
如何查看sh的路径?
which - shows the full path of (shell) commands.
shell头的写法
#!/bin/bash
#!/bin/sh
名称叫做【shebang】,因为#发音是sharp,!发音是bang。它指定了shell的解释器。