什么时候#!/bin/bash
比#!/bin/sh
在shell脚本中更合适?
vim
它将突出显示bash
-isms #!/bin/sh
。我仅将其更改为bash
如果事情变得毛茸茸以开始需要bash功能。
$(...)
特别令人讨厌。此外,它们中的一些微妙[ <(...)
和cmd >& file
没有得到任何错误高亮显示,例如,他们只是没有特殊高亮他们的意思,带或不带g:is_bash
]
什么时候#!/bin/bash
比#!/bin/sh
在shell脚本中更合适?
vim
它将突出显示bash
-isms #!/bin/sh
。我仅将其更改为bash
如果事情变得毛茸茸以开始需要bash功能。
$(...)
特别令人讨厌。此外,它们中的一些微妙[ <(...)
和cmd >& file
没有得到任何错误高亮显示,例如,他们只是没有特殊高亮他们的意思,带或不带g:is_bash
]
Answers:
简而言之:
有几个Shell实现POSIX sh规范的超集。在不同的系统上,/bin/sh
可能是指向ash,bash,dash,dash,ksh,zsh和&c的链接。(尽管它将始终与sh兼容-永远不会csh或fish。)
只要您sh
仅坚持使用功能,就可以使用(并且甚至应该使用)功能#!/bin/sh
,并且脚本可以正常运行,无论它是哪个外壳。
如果你开始使用Bash特殊功能(如数组),你应该特别要求的bash -因为,即使/bin/sh
已经调用上的bash 你的系统,它可能无法在其他人的系统,你的脚本将不会运行那里。(当然,zsh和ksh也是如此。)您可以使用shellcheck来识别bashisms。
即使该脚本仅供个人使用,您也可能会注意到,某些操作系统/bin/sh
在升级过程中会发生变化-例如在Debian上它曾经是bash,但后来被极小的破折号所取代。使用bashisms但#!/bin/sh
突然中断的脚本。
然而:
甚至#!/bin/bash
不是很正确。在不同的系统上,bash可能驻留在/usr/bin
或/usr/pkg/bin
或中/usr/local/bin
。
一个更可靠的选项是#!/usr/bin/env bash
,它使用$ PATH。(尽管env
也没有严格保证该工具本身,/usr/bin/env
但它仍然可以在比其他系统更多的系统/bin/bash
上使用。)
/bin/sh
开始运行,它将尝试模拟sh
功能(请参见手册页),不确定bash特定的功能在此模式下是否可用。env
该工具是posix工具,应该在大多数发行版中都可以找到,但是我不确定,因为有些人可能不尊重posix。
#!
脚本工作的可移植方式吗?
echo foo ^ cat
发射foo ^ cat
在POSIX SH,并且仅发射foo
布赫纳(作为^
一个管道字符那里)。
使用与您实际用于开发和调试脚本的外壳相对应的shebang。也就是说,如果您的登录shell是bash
,并且您在终端中以可执行文件身份运行脚本,请使用#!/bin/bash
。不要仅仅假设既然您还没有使用数组(或者bash
您知道的任何功能),那么就可以安全地选择所需的任何shell。外壳之间有许多细微的差异(echo
,函数,循环,您可以将其命名),如果不进行适当的测试就无法发现它们。
考虑一下:如果您离开#!/bin/bash
而用户没有,则他们将看到清晰的错误消息,例如
Error: /bin/bash not found
大多数用户可以通过安装适当的软件包在一分钟内解决此问题。另一方面,如果您将shebang替换为,#!/bin/sh
并且在/bin/sh
与的符号链接为的系统上对其进行测试/bin/bash
,则没有此功能的用户bash
会遇到麻烦。他们很可能会看到类似以下错误消息:
Error in script.sh line 123: error parsing token xyz
这可能要花几个小时才能解决,也没有任何线索说明他们应该使用哪个外壳。
您并不需要在shebang中使用其他shell的理由并不多。原因之一是您使用的外壳不普及。另一个是sh
在某些系统上获得更快的性能,而您的脚本将成为性能瓶颈。在这种情况下,请使用目标外壳程序彻底测试脚本,然后更改shebang。
#! /bin/sh
。永远不要在shell脚本中使用bash(或zsh,fish或...)扩展名。
您只应该编写可与任何外壳程序语言实现一起使用的外壳程序脚本(包括与外壳程序本身一起使用的所有“实用程序”程序)。这些天,您可能可以将POSIX.1-2001(不是 -2008)作为Shell和实用程序功能的权威,但是请注意,可能有一天您可能会被要求将脚本移植到旧系统(例如Solaris)或AIX),其外壳和实用程序大约在1992年被冻结。
是的,认真。
事情是这样的:Shell是一种糟糕的编程语言。它唯一要做的就是确保每个 Unix安装都具有/bin/sh
唯一的脚本解释器。
这是另一回事:随机选择的Unix安装上更有可能使用Perl 5核心解释器(/usr/bin/perl
)的某些迭代。其他好的脚本语言(Python,Ruby,node.js等-与shell相比,我什至包括PHP和Tcl在内)也大致可以作为bash和其他扩展shell使用。(/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash
因此,如果您可以选择编写bash脚本,则可以选择使用一种并不糟糕的编程语言。
现在,简单的 shell脚本(这种脚本只是从cron作业或某些东西中按顺序运行几个程序),将它们保留为shell脚本没有任何问题。但是简单的shell脚本甚至不需要数组或函数[[
。而且,只有在别无选择时,才应该编写复杂的 Shell脚本。例如,Autoconf脚本仍然是正确的Shell脚本。但是这些脚本必须在与要配置的程序相关的所有形式上运行/bin/sh
。这意味着他们不能使用任何扩展名。这些天您可能不必在意旧的专有Unix,但是您可能应该在意当前的开源BSD,其中有些没有安装bash
默认情况下,以及仅给您最少的shell和的嵌入式环境busybox
。
总之,当您发现自己想要的功能在便携式Shell语言中不可用时,这表明该脚本变得太复杂而无法保留Shell脚本。改用更好的语言重写它。
sh
。但是,这与声明永远不要使用其他外壳程序相去甚远。每天有成千上万个(可能更多)脚本编写,其中绝大部分只能在一台计算机上运行。您的建议对生产代码有意义,但对大多数脚本所编写的日常“ sysdaminy”作业却没有意义。如果我知道我的脚本只能由我使用并且在Linux机器上使用,bash很好。
通常,如果时间比功能更重要,则可以使用速度更快的Shell。sh通常被别名为破折号,并且倾向于用于root的cron任务或批处理操作,其中每一秒都非常重要。
bash
函数和语法而不是sh
函数和语法时。