什么时候#!/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函数和语法时。