关于set
我们经常在shell脚本中看到 set
命令,刚好有小伙伴感兴趣问了我,我写脚本其实也是只用set -x
、set -e
和set -u
这三个多一点,其他的比较少涉及,但是刚好系统了解下。了解一个命令我们可以直接执行帮助命令:
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
set: set [--abefhkmnptuvxBCHP] [-o 选项名] [--] [参数 ...] Set or unset values of shell options and positional parameters. (设置或取消设置 shell 选项和位置参数的值。) Change the value of shell attributes and positional parameters, or display the names and values of shell variables. (更改 shell 属性和位置参数的值,或显示 shell 变量的名称和值。) Options: -a 标示已修改的变量,以供输出至环境变量。 -b 使被中止的后台程序立刻回报执行状态。 -e 若指令传回值不等于0,则立即退出shell。 -f 取消使用通配符。 -h 自动记录函数的所在位置。 -k 指令所给的参数都会被视为此指令的环境变量。 -m 使用监视模式。 -n 只读取指令,而不实际执行。 -o 选项名称 设置与选项名称对应的变量: allexport same as -a braceexpand same as -B emacs use an emacs-style line editing interface errexit same as -e errtrace same as -E functrace same as -T hashall same as -h histexpand same as -H history enable command history ignoreeof the shell will not exit upon reading EOF interactive-comments allow comments to appear in interactive commands keyword same as -k monitor same as -m noclobber same as -C noexec same as -n noglob same as -f nolog currently accepted but ignored notify same as -b nounset same as -u onecmd same as -t physical same as -P pipefail the return value of a pipeline is the status of the last command to exit with a non-zero status, or zero if no command exited with a non-zero status posix change the behavior of bash where the default operation differs from the Posix standard to match the standard privileged same as -p verbose same as -v vi use a vi-style line editing interface xtrace same as -x -p Turned on whenever the real and effective user ids do not match. Disables processing of the $ENV file and importing of shell functions. Turning this option off causes the effective uid and gid to be set to the real uid and gid. (我也看不明白,翻译:每当真实和有效的用户 ID不匹配时打开。 禁用 $ENV 文件的处理和 shell 函数的导入。 关闭此选项会导致将有效的uid 和 gid 设置为真实的 uid 和 gid。) -t 执行完随后的指令,即退出shell。 -u 当执行时使用到未定义过的变量,则显示错误信息。 -v 显示shell所读取的输入值。 -x 执行指令后,会先显示该指令及所下的参数。 -B shell将会执行花括号扩展(自行google这个名词)。 -C 转向所产生的文件无法覆盖已存在的文件。 -E trap(自己google)的ERR将会由shell函数继承。 -H shell可利用"!"加<指令编号>的方式来执行history中记录的指令。 -P 启动-P参数后,执行指令时,会以实际的文件或目录来取代符号连接。 -T trap(自己google)的DEBUG和RETURN将会由shell函数继承。 -- Assign any remaining arguments to the positional parameters. If there are no remaining arguments, the positional parameters are unset.(我也看不明白,翻译: 将任何剩余参数分配给位置参数。 如果没有剩余参数,则取消设置位置参数。) - Assign any remaining arguments to the positional parameters. The -x and -v options are turned off.(我也看不明白,翻译: 将任何剩余参数分配给位置参数。 -x 和 -v 选项被覆盖关闭。) Using + rather than - causes these flags to be turned off. The flags can also be used upon invocation of the shell. The current set of flags may be found in $-. The remaining n ARGs are positional parameters and are assigned, in order, to $1, $2, .. $n. If no ARGs are given, all shell variables are printed. Exit Status: Returns success unless an invalid option is given.
上面我大概翻译了下,有一小部分我自己也不懂,其实大部分我们都用不到,用的最频繁的是set -e
,set -x
和set -u
,我们重点把这几个说一下:
set -x
默认情况下,脚本执行后屏幕只显示运行结果,没有其他内容。如果多个命令连续执行,它们的运行结果就会连续输出。有时会分不清,某一段内容是什么命令产生的。set -x用来在运行结果之前,先输出执行的那一行命令。:
|
|
输出结果:
+ a=1
+ b=foo
+ echo foo
foo
可以看到,执行echo foo 命令会先打印出来,行首以+
表示。
set -e
如果脚本里面有运行失败的命令(返回值非0),Bash 默认会继续执行后面的命令。例如:
|
|
输出结果:
行3: foo: 未找到命令
bar
脚本只是报错,但是并没有终止执行,这种行为很不利于脚本安全和除错。set -e从根本上解决了这个问题,它使得脚本只要发生错误,就终止执行。
|
|
输出结果:
行4: foo: 未找到命令
这样脚本就直接退出了。
set -e 根据返回值来判断一个命令是否运行失败,但是某些命令的非零返回值可能不表示失败,或者开发者希望在命令失败的情况下,脚本继续执行下去。这时可以暂时关闭set -e,该命令执行结束后,再重新打开set -e。
|
|
输出结果:
行4: foo: 未找到命令
bar
行7: foo1: 未找到命令
可以看到echo bar
被执行了,但是echo bar1
没有被执行。
set -u
执行脚本的时候,如果遇到不存在的变量Bash 默认忽略它。例如:
|
|
输出结果:
bar
可以看到$foo 虽然不存在,但没有报错,大多数情况下这不是开发者想要的行为,遇到变量不存在脚本应该报错,而不是一声不响地往下执行。
脚本在头部加上set -u,脚本遇到不存在的变量就会报错并停止执行。
|
|
输出结果:
行4: foo: 未绑定的变量