脚本在使用“#!/bin/sh”运行时不起作用

eve*_*ner 6 command-line bash scripts

我有一个使用 shebang : 的脚本#!/bin/sh,但是当我在 Ubuntu 14.04 终端中运行它时,它不起作用,并且它说某些行具有意外的运算符。

我在 MacOSX 中的朋友可以使用#!/bin/shshebang运行该脚本。

我试图将 shebang 更改为#!/usr/bin/env bash,突然间,脚本起作用了!这里究竟发生了什么?

我真的希望我也可以运行!#/bin/shshebang,这样我就不需要更改我拥有的每个脚本。

mur*_*uru 25

您在另一台计算机上的朋友可能使用的操作系统已/bin/sh链接到/bin/bash. 在 Ubuntu(实际上是 Debian 和大多数 Debian 衍生版)中,/bin/sh不是链接到/bin/bash,而是链接到/bin/dash,它不支持许多bash特定的功能,但速度要快得多。

在 Arch Linux 上:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Sep 28 15:26 /bin/sh -> bash
Run Code Online (Sandbox Code Playgroud)

在 Ubuntu 上:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 19  2014 /bin/sh -> dash
Run Code Online (Sandbox Code Playgroud)

正确的做法

如果您使用shebang,请认真对待。由于您的脚本包含bash-isms,请/bin/bash在 shebang 中使用。或者编写可移植的、符合 POSIX 的代码。

您可以使用这篇 LWN 文章中checkbashisms提到的程序来加快此过程。它是包的一部分,所以先安装它:devscripts

sudo apt-get install devscripts
Run Code Online (Sandbox Code Playgroud)

因此:

checkbashisms /path/to/script.sh || sed -i '1 s;/bin/sh;/bin/bash;' /path/to/script.sh
Run Code Online (Sandbox Code Playgroud)

您可以将其转换为脚本(例如convert.sh):

#! /bin/sh

for i
do
    checkbashisms "$i"
    if [ $? = "1" ]
    then
        sed -i '1 s;/bin/sh;/bin/bash;' "$i"
    fi
done
Run Code Online (Sandbox Code Playgroud)

的具体返回码1意味着checkbashisms发现了一个可能的bashism,其他返回值表示其他问题(文件不可读、缺少shebang等),因此我们可以检查该特定返回值。

然后调用它:

./convert.sh /path/to/first/script.sh /path/to/second/script.sh
# or 
./convert.sh *.sh
# or
find . -iname '*.sh' -exec ./convert.sh {} +
Run Code Online (Sandbox Code Playgroud)

错误的做法

替换/bin/sh为指向/bin/bash.

推荐阅读: