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


18

我知道我可以用作第一行脚本来调用所需的shell。

#!/bin/sh被推荐,如果所有的UNIX系统的兼容性是一个绝对的要求?

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


1
可能值得注意的是,许多发行版已经开始合并/bin和合并/usr/bin。结果,如今最好使用#!/usr/bin/env <shname>可移植性。
HalosGhost 2015年

Answers:


15

对于初学者,如果您可以假设已预先安装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"

而在传统的壳方言中,您必须求助于:

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

但是关于双括号的最好之处在于它们允许使用正则表达式进行匹配。该猛砸黑客维基会给你很多的技巧在那个方向。

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

对子壳使用反引号也可以,尽管有些过时了。但是,$(command ...)调用的嵌套功能更加方便,因为您不必在不同的子Shell级别上转义许多事情。

这些只是Bash在传统的常见POSIX sh语法上为您提供的一些内容。

但是,如果您想在shell上拥有更多功能(不仅仅是在脚本中),还可以看看zsh


Bash是一个非常有用的工具,但请注意不要将其用于启动可能容易受到Bash脚本错误影响的服务,例如access.redhat.com/security/cve/CVE-2014-6271。坚持sh执行此类任务。
Rick-777

1
Rick-777漏洞被严重夸大了,我认为您的评论是FUD。如果系统服务在bash下运行,则绝不会受到该bug的攻击。如果它启动了bash进程,同时允许远程用户直接访问一个或多个环境变量(例如在FastCGI中),甚至仅在未修补的bash版本上访问,则它容易受到该bug的攻击。在sh链接到的系统上bash,不能通过使用缓解漏洞sh
Score_

11

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

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

如果要使用bash扩展名,则在所有系统上最安全的方法是指定#!/bin/bash; 这样,您就明确声明了对的依赖bash。您需要在Debian和Ubuntu上执行此操作。作为一个额外的好处,当作为开始/bin/sh bash去激活一些扩展(见的描述bashPOSIX模式的详细信息); 因此#!/bin/bash必须进行指定才能充分利用bash

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


5

是的,OSX和Linux都将随附/bin/bash。您应该绝对安全。但是,那不是 POSIX。POSIX Shell /bin/sh最多(所有)系统上,这是最可移植的方法,也是唯一兼容POSIX的方法。

请注意,尽管在许多系统上/bin/sh指向bash,在其他系统上却可以指向不同的外壳。例如,这是dash在Debian和Ubuntu上的符号链接。同样,即使/bin/sh是的链接bash,当它被称为sh(来自man bash,强调我的)时,shell的行为也会改变:

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


2

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

实际上比这差得多。如果您需要与所有 Unix系统兼容,那么其中包括Solaris和AIX之类的东西会冻结其大约在1995年的外壳环境。这意味着您必须使用诸如老式sort +N语法之类的东西- 系统已经废弃!而且这也意味着没有外壳函数,没有数组,没有[[ ... ]],没有${foo#glob},没有$(( ... ))用于算术,可能没有$( ... )样式的命令替换,对输入量有多大的小且未记录的上限...

您也许可以不用担心那么多的兼容性,但是如果一开始它甚至是个问题,我强烈建议您考虑使用一种不如Shell糟糕的语言。基本的Perl解释器比Bash 可能可用。


谢谢。如最初所说,“在我看来,我唯一关心的OS是Ubuntu(Debian)和OSX。”。这些是我过去5年中使用过的仅有2个系统(并且我经常使用它们),所以这就是为什么我要编写仅在它们上工作的Shell脚本。我根本不需要通用脚本及其会带来的限制。
迈克尔·杜兰特

@MichaelDurrant在这种情况下,您也不需要编写外壳脚本。相反,您不需要完全可移植性时,可以选择使用多种更好的脚本语言。
zwol 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.