这八个建议,来源于键者几年来编写 shell 脚本的一些经验和教训。事实上开始写的时候还不止这几条,后来思索再三,去掉几条无关痛痒的,最后剩下八条。毫不夸张地说,每条都是精挑细选的,虽然有几点算是老生常谈了。
1. 指定bash
shell 脚本的第一行,#!之后应该是什么?如果拿这个问题去问别人,不同的人的回答可能各不相同。
我见过/usr/bin/env bash,也见过/bin/bash,还有/usr/bin/bash,还有/bin/sh,还有/usr/bin/env sh。这算是编程界的“'茴'字四种写法”了。
在多数情况下,以上五种写法都是等价的。但是,写过程序的人都知道:“少数情况”里往往隐藏着意想不到的坑。
如果系统的默认 shell 不是 bash 怎么办?比如某 Linux 发行版的某个版本,默认的 sh 就不是 bash。
如果系统的 bash 不是在 /usr/bin/bash 怎么办?
我推荐使用 /usr/bin/env bash 和 /bin/bash。前者通过env添加一个中间层,让env在$PATH中搜索bash;后者则是官方背书的,约定俗成的 bash 位置,/usr/bin/bash不过是指向它的一个符号链接。
2. set -e 和 set -x
OK,经过一番讨论,现在第一行定下来了。接下来该开始写第二行了吧?
且慢!在你开始构思并写下具体的代码逻辑之前,先插入一行set -e和一行set -x。
set -x会在执行每一行 shell 脚本时,把执行的内容输出来。它可以让你看到当前执行的情况,里面涉及的变量也会被替换成实际的值。
set -e会在执行出错时结束程序,就像其他语言中的“抛出异常”一样。(准确说,不是所有出错的时候都会结束程序,见下面的注)
注:set -e结束程序的条件比较复杂,在man bash里面,足足用了一段话描述各种情景。大多数执行都会在出错时退出,除非 shell 命令位于以下情况:
一个 pipeline 的非结尾部分,比如 error | ok
一个组合语句的非结尾部分,比如 ok && error || other
一连串语句的非结尾部分,比如 error; ok
位于判断语句内,包括test、if、while等等。
这两个组合在一起用,可以在 debug 的时候替你节省许多时间。出于防御性编程的考虑,有必要在写第一行具体的代码之前就插入它们。扪心自问,写代码的时候能够一次写对的次数有多少?大多数代 码,在提交之前,通常都经历过反复调试修改的过程。与其在焦头烂额之际才引入这两个配置,不如一开始就给 debug 留下余地。在代码终于可以提交之后,再考虑是否保留它们也不迟。
3. 带上shellcheck
好了,现在我已经有了三行(样板)代码,具体的业务逻辑一行都没写呢。是不是该开始写了?
新闻热点
疑难解答