使用 #!/bin/sh 或 #!/bin/bash 实现 Ubuntu-OSX 兼容性以及易用性和 POSIX

使用 #!/bin/sh 或 #!/bin/bash 实现 Ubuntu-OSX 兼容性以及易用性和 POSIX

我知道我可以使用其中任何一个作为脚本的第一行来调用所需的 shell。

#!/bin/sh如果与所有 UNIX 系统兼容是绝对要求的话,会推荐吗?

就我而言,我唯一关心的操作系统是 Ubuntu (Debian) 和 OSX。鉴于此,我可以使用#!/bin/bash并保证它可以在两个系统上运行吗?
这是否也会使使用具有更现代、更清晰的命令语法的脚本变得更容易?使用#!/bin/sh也与使用 POSIX 有关吗?

答案1

对于初学者来说,如果您可以假设预安装了 Bash(据我所知,您列出的所有系统上都是这种情况),请使用以下 hashbang 来兼容:

#!/usr/bin/env bash

这会调用bash发生的任何配置,无论它是在/bin或中/usr/local/bin

虽然在大多数系统上(包括 AIX、Solaris、几种 BSD 风格),bash最终位于不同的位置,但env总是最终位于/usr/bin/env.然而,这个技巧不是我的,而是来自 Bash Cookbook 的作者。

不管怎样,是的,Bash 允许您使用一些“现代”功能,让您的生活更轻松。

例如双括号:

[[ -f "/etc/debian_version" ]] && echo "This is a Debian flavor"

而在传统的 shell 方言中,你必须求助于:

test -f "/etc/debian_version" && echo "This is a Debian flavor"

但双括号的最大优点是它们允许使用正则表达式进行匹配。这Bash 黑客维基将会给你很多这方面的技巧。

您还可以使用非常方便的表达式,例如$((2**10))与语法内联的其他算术表达式$((expression))

对子 shell 使用反引号很好,尽管有点过时。但是调用的嵌套功能$(command ...)更加方便,因为您不必在不同的子 shell 级别转义许多东西。

这些只是 Bash 相对于传统常见 POSIX 语法所提供的一些功能sh

但如果您想在 shell 上获得更多功能(不仅仅是在脚本中),也可以看看zsh.

答案2

在 Debian 和 Ubuntu 中,/bin/shdash,它是 POSIX 兼容的 shell。如果指定#!/bin/sh,则必须将自己限制为脚本中的 POSIX 语句。 (优点是dash启动速度比 更快bash,因此您的脚本可以在更短的时间内完成其工作。)

在许多(大多数?)其他 Linux 系统上,/bin/sh是,这就是为什么许多脚本使用扩展名作为 shebang 行bash编写的原因。#!/bin/shbash

如果您想使用bash扩展,所有系统上最安全的方法是指定#!/bin/bash;这样你就明确地表明了你对bash.你需要在 Debian 和 Ubuntu 上执行此操作。作为额外的好处,当启动时/bin/sh bash会停用一些扩展(请参阅bashPOSIX模式说明了解详情);因此,#!/bin/bash为了充分发挥bash.

在 OS X 上/bin/bash也可用,并且/bin/shbash.在那里指定#!/bin/bash也可以正常工作。

答案3

是的,OSX 和 Linux 都将附带/bin/bash.你应该绝对安全。然而,那就是不是POSIX。 POSIX shell 存在于/bin/sh大多数(所有?)系统上,这是最可移植的方法,也是 POSIX 兼容的唯一方法。

请注意,虽然在许多系统上/bin/sh指向bash,但在其他系统上它可以指向不同的 shell。dash例如,它是 Debian 和 Ubuntu 上的符号链接。另外,即使/bin/sh是 的链接bash,当它被调用时,shell 的行为也会发生变化sh(来自man bash,强调我的):

如果使用 sh 名称调用 bash,它会尝试尽可能模仿 sh 历史版本的启动行为,同时也符合 POSIX 标准。 当作为交互式登录 shell 或带有 --login 选项的非交互式 shell 调用时,它首先尝试按顺序从 /etc/profile 和 ~/.profile 读取并执行命令。 --noprofile 选项可用于抑制此行为。当使用名称 sh 作为交互式 shell 调用时,bash 会查找变量 ENV,如果定义了该变量
,则扩展其值,并使用扩展后的值作为要读取和执行的文件的名称。由于作为 sh 调用的 shell 不会尝试从任何其他启动文件读取和执行命令,因此 --rcfile 选项不起作用。 使用名称 sh 调用的非交互式 shell 不会尝试读取任何其他启动文件。当作为 sh 调用时,bash 在读取启动文件后进入 posix 模式。

答案4

如果与“所有 Unix 系统”的兼容性是绝对要求——如果不是,你为什么要编写 shell 脚本?-- 那么,是的,您应该使用#! /bin/sh,因为不保证安装 Bash任何地方,更不用说在/bin.

实际上比这糟糕得多。如果您需要兼容性全部Unix 系统,包括 Solaris 和 AIX 等冻结他们的 shell 环境大约 1995 年。这意味着你必须使用老式sort +N语法之类的东西——即较新的系统掉线了!它还意味着没有 shell 函数,没有数组,没有[[ ... ]],没有${foo#glob},没有$(( ... ))算术,可能没有$( ... )-style 命令替换,小且未记录的输入大小上限,......

你也许可以摆脱不打扰兼容性很好,但如果这从一开始就是一个问题,我强烈建议您考虑一种比 shell 更安全的语言。基本的 Perl 解释器是更多的可能比 Bash 更可用。

相关内容