Bash 使用需要避免掉坑的地方

查看原文

本文列出了五十多项在使用 Bash 的时候需要注意的地方,Bash 是如此强大但又非常容易出错,一不小心就会删干净你计算机中没备份的文件。如果说人在不停地试错中学习,本文给出了绝佳的避免犯错的清单。

  • 通配符(*),空格( ), 有 leading-dash (-打头的文件), 有 ! 是很多错误的本源。这些东西让 bash 很魔法,也很魔幻。每一行 sh 代码都要好好想想字符串或者变量中是否会存在被转义的可能,如果会,配置好环境变量或者加上 quote。
    • for i in 后面要用通配符 或者使用 find -exec.
    • cp 的时候 "./$file" 这样比较靠谱。
    • [[ $var == [[ 比较人性能识别 $var 的空格
    • [ "$var" = [ 就比较不人性了,得加 "$var" quote.
    • 很多人没有注意到 if [ a = b ] 的 if 后面有个空格,一定要注意啊,[ 是个命令,不是高级语言的 (.
    • echo "$foo" 会比 echo $foo 更安全,万一 $foo 里面有空格呢?
    • a=b 才是正解, a="b"是上上解,写成 a = b, a =b, a= b 都是不对的
    • 交互模式下 echo "hello world\!" 才能避免 ! 被 histexpand, 或者干脆 'hello world!' 或者加上 set +H
    • ~ 只有在 token 的第一个字符才会被替换成 $HOME, 安全起见,还是写成 $HOME 靠谱一些。
  • 一些 shell 的语法长的和高级语言差不多,但其实不是
    • 上面的 [, [[ 是一个例子
    • cmd1 && cmd2 || cmd3 <- 这个和 if (cmd1) then cmd2 else cmd fi 是不完全等价的,&& 会去看后面的命令是否返回 0,否则 cmd3 还是会被调用。
    • function foo() { ... } 不一定都能工作啦,看你用什么 shell,但是 foo() { ... } 都肯定可以移植运行成功的。
    • read $foo 是错的,得写成 IFS= read -r foo, 尽管你取值的时候要用 $foo, 以及记得加quote 如果不安全的话。
    • cat file | sed s/foo/bar/ > file 很多人都会一不小心写出来的东西:读文件,经过管道,写回文件,这只会让 file 的内容被清空。比较安全的做法是写到 tmpfile 在 mv 回来,或者对自己的 sed 技术够自信的话可以 edit in-place.
    • cd /foo; bar 很多人都假定 bash 像高级语言一样,出错后崩溃就不往下执行了,并非如此。你要么得提前配置 set -e, 要么这里写成 cd /foo && bar, 或者 cd /foo !! exit 1; bar

衍生思考:死ね,Bash!