我知道我可以使用其中任何一个作为脚本的第一行来调用所需的 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/sh
是dash
,它是 POSIX 兼容的 shell。如果指定#!/bin/sh
,则必须将自己限制为脚本中的 POSIX 语句。 (优点是dash
启动速度比 更快bash
,因此您的脚本可以在更短的时间内完成其工作。)
在许多(大多数?)其他 Linux 系统上,/bin/sh
是,这就是为什么许多脚本使用扩展名作为 shebang 行bash
编写的原因。#!/bin/sh
bash
如果您想使用bash
扩展,所有系统上最安全的方法是指定#!/bin/bash
;这样你就明确地表明了你对bash
.你需要在 Debian 和 Ubuntu 上执行此操作。作为额外的好处,当启动时/bin/sh
bash
会停用一些扩展(请参阅bash
POSIX模式说明了解详情);因此,#!/bin/bash
为了充分发挥bash
.
在 OS X 上/bin/bash
也可用,并且/bin/sh
是bash
.在那里指定#!/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 更可用。