如何编写具有错误处理功能的可移植 shell 脚本

era*_*man 6 bash

我在使用 编写可移植的、功能齐全的 shell shell 脚本方面取得了相对较好的成功/bin/sh,例如:

#!/bin/sh
trap 'echo "Error on line $LINENO"; exit 1' ERR
while read LINE
do
  echo "+ $LINE"
done < file.txt
Run Code Online (Sandbox Code Playgroud)

这适用于 BSD 因为/bin/sh通常是ksh

$ ls -li /bin/{sh,ksh}
26768 -r-xr-xr-x  3 root  bin  418612 Jun 18 17:41 /bin/ksh
26768 -r-xr-xr-x  3 root  bin  418612 Jun 18 17:41 /bin/sh
Run Code Online (Sandbox Code Playgroud)

虽然在 MacOS 和许多 Linux 发行版上只是简单地符号链接/bin/shbash

$ ls -li /bin/{sh,bash}
17170438 -rwxr-xr-x 1 root root 938832 Jul 18  2013 /bin/bash
17170540 lrwxrwxrwx 1 root root      4 Feb 19 12:42 /bin/sh -> bash
Run Code Online (Sandbox Code Playgroud)

如果这两个条件都成立,那么我可以使用 KSH 和 BASH 通用的相对丰富的功能集。在 Ubuntu 上,默认 shell 仅支持POSIX 功能。是否仍然可以编写一个也包含错误处理的跨平台 shell 脚本?

编辑 (2014-08-18)

我想出的解决方案是如果给定的 shell 不理解 ERR 陷阱,则自动升级脚本

#!/bin/sh
trap 'echo "Error on line $LINENO"; exit 1' ERR || exec bash $0 "$@"
Run Code Online (Sandbox Code Playgroud)

这允许我编写合理的可移植 shell 脚本,如果默认 shell 不支持 KSH 功能,则只需要 bash。

Flo*_*sch 3

如果您想编写可移植的 shell 脚本,您应该坚持使用 POSIX,因为这是 Unix 世界中最可靠的标准。

依赖于/bin/shBourne shell 以外的任何东西都是糟糕的风格,并且可能迟早会崩溃。

由于 POSIX 不支持陷阱,ERR您必须使用||. 例如:

#!/bin/sh

error(){
 echo "Error at $1"; exit 1   ## we don't have $LINENO in POSIX
}

while read LINE
do
  echo "+ $LINE"
  false
done < file.txt || error "while loop"
Run Code Online (Sandbox Code Playgroud)