Shell 脚本零碎笔记

set的基本用法,写出更安全的 Bash 脚本

  • set -u: 脚本在头部加上它,遇到不存在的变量就会报错,并停止执行
  • set -x: 用来在运行结果之前,先输出执行的那一行命
  • set -e: 它使得脚本只要发生错误,就终止执行
    某些命令的非零返回值可能不表示失败,或者开发者希望在命令失败的情况下,脚本继续执行下去。这时可以暂时关闭 set +e,该命令执行结束后,再重新打开set -e
    还有一种方法是使用command || true,使得该命令即使执行失败,脚本也不会终止执行
    set -e有一个例外情况,就是不适用于管道命令,此时需要用到下面用法
  • set -o pipefail 只要一个子命令失败,整个管道命令就失败,脚本就会终止执行
  • set -n: 等同于set -o noexec,不运行命令,只检查语法是否正确。
  • set -f: 等同于set -o noglob,表示不对通配符进行文件名扩展。
  • set -v: 等同于set -o verbose,表示打印 Shell 接收到的每一行输入

总结

重点介绍的set命令的四个参数,一般都放在一起使用

1
2
3
4
5
6
# 写法一
set -euxo pipefail

# 写法二
set -eux
set -o pipefail

这两种写法建议放在所有 Bash 脚本的头部

另一种办法是在执行 Bash 脚本的时候,从命令行传入这些参数

Bash 脚本除错

在使用脚本删除某个目录文件时:
尽量使用下面的写法

1
[[ -d $dir_name ]] && cd $dir_name && rm *

上面代码中,先判断目录$dir_name是否存在,然后才执行其他操作

如果不放心删除什么文件,可以先打印出来看一下

1
[[ -d $dir_name ]] && cd $dir_name && echo rm *

上面命令中,echo rm *不会删除文件,只会打印出来要删除的文件

mktemp 命令,trap 命令

生成临时文件应该遵循下面的规则:

  • 创建前检查文件是否已经存在
  • 确保临时文件已成功创建
  • 临时文件必须有权限的限制
  • 临时文件要使用不可预测的文件名
  • 脚本退出时,要删除临时文件(使用 trap 命令)

mktemp 命令

Bash 脚本使用mktemp命令的用法如下

1
2
3
4
#!/bin/bash

TMPFILE=$(mktemp)
echo "Our temp file is $TMPFILE"

为了确保临时文件创建成功,mktemp命令后面最好使用 OR 运算符(||),保证创建失败时退出脚本

1
2
3
4
#!/bin/bash

TMPFILE=$(mktemp) || exit 1
echo "Our temp file is $TMPFILE"

为了保证脚本退出时临时文件被删除,可以使用trap命令指定退出时的清除操作

1
2
3
4
5
6
#!/bin/bash

trap 'rm -f "$TMPFILE"' EXIT

TMPFILE=$(mktemp) || exit 1
echo "Our temp file is $TMPFILE"
  • -d: 可以创建一个临时目录
  • -p: 可以指定临时文件所在的目录
  • -t: 可以指定临时文件的文件名模板,模板的末尾必须至少包含三个连续的X字符,表示随机字符,建议至少使用六个X,默认的文件名模板是tmp.后接十个随机字符
1
>$ mktemp -t mytemp.XXXXXXX

trap 命令

trap命令用来在 Bash 脚本中响应系统信号,命令格式如下

1
>$ trap [动作] [信号1] [信号2] ...

“动作”是一个 Bash 命令,“信号”常用的有以下几个

  • HUP:编号1,脚本与所在的终端脱离联系。
  • INT:编号2,用户按下 Ctrl + C,意图让脚本中止运行。
  • QUIT:编号3,用户按下 Ctrl + 斜杠,意图退出脚本。
  • KILL:编号9,该信号用于杀死进程。
  • TERM:编号15,这是kill命令发出的默认信号。
  • EXIT:编号0,这不是系统信号,而是 Bash 脚本特有的信号,不管什么情况,只要退出脚本就会产生。
    trap命令响应EXIT信号的写法如下:
1
>$ trap 'rm -f "$TMPFILE"' EXIT

上面命令中,脚本遇到EXIT信号时,就会执行rm -f "$TMPFILE"
trap 命令的常见使用场景,就是在 Bash 脚本中指定退出时执行的清理命令

注意,trap命令必须放在脚本的开头。否则,它上方的任何命令导致脚本退出,都不会被它捕获

如果trap需要触发多条命令,可以封装一个 Bash 函数

1
2
3
4
5
6
7
function egress {
command1
command2
command3
}

trap egress EXIT

为了方便 Debug,有时在启动 Bash 的时候,可以加上启动参数

  • -n:不运行脚本,只检查是否有语法错误
  • -v:输出每一行语句运行结果前,会先输出该行语句
  • -x:每一个命令处理完以后,先输出该命令,再进行下一个命令的处理

使用下面的代码,可以设定其后文本的颜色:

  • \033[0;30m:黑色
  • \033[1;30m:深灰色
  • \033[0;31m:红色
  • \033[1;31m:浅红色
  • \033[0;32m:绿色
  • \033[1;32m:浅绿色
  • \033[0;33m:棕色
  • \033[1;33m:黄色
  • \033[0;34m:蓝色
  • \033[1;34m:浅蓝色
  • \033[0;35m:粉红
  • \033[1;35m:浅粉色
  • \033[0;36m:青色
  • \033[1;36m:浅青色
  • \033[0;37m:浅灰色
  • \033[1;37m:白色

除了设置前景颜色,Bash 还允许设置背景颜色:

  • \033[0;40m: 蓝色
  • \033[1;44m: 黑色
  • \033[0;41m: 红色
  • \033[1;45m: 粉色
  • \033[0;42m: 绿色
  • \033[1;46m:青色
  • \033[0;43m:棕色
  • \033[1;47m:浅灰色