-- TOC --
set命令是 Bash 脚本的重要环节,却常常被忽视,导致脚本的安全性和可维护性出问题。
set是一个bash builtin命令,查看帮助 help set
。参数用-
表示打开,+
表示关闭!
Set or unset values of shell options and positional parameters. Change the value of shell attributes and positional parameters, or display the names and values of shell variables.
在命令行直接使用set命令,不仅仅可以看到所有的环境变量,还能看到所有全局定义,比如shell函数。(如果只看环境变量,用env
命令或printenv
命令)
$ echo $-
显示出来的字符串中的每一个字符,就是当前bash的set配置项!
-u Treat unset variables as an error when substituting.
默认bash脚本在执行时,遇到不存在的变量,会忽略,继续执行后面的脚本代码。这样的行为模式有时并不是我们所希望的,我们希望像真正的代码那样,遇到不存在的变量,报错!此时,就需要使用 set -u
。
$ echo $ABCD
# a blank line here
$ set -u
$ echo $ABCD
-bash: ABCD: unbound variable
把 set -u
放在.sh文件的前面,可以更容易发现脚本的错误。
等价的写法: set -o nounset
-x Print commands and their arguments as they are executed.
默认情况下,脚本的执行只输出运行打印,而没有其它内容。如果连续多个命令执行,产生了很多输出,我们会难以分清哪些输出对应哪个命令,解决这个问题的方法,就是 set -x
,然后在执行每一条命令的时候,会自动输出命令本身。
另外,还可以通过bash的命令行参数,来实现相同的功能:
$ bash -x <script>
-e Exit immediately if a command exits with a non-zero status.
默认情况,bash脚本在执行过程中,如果某个命令执行失败,其返回为非0,脚本会继续执行,不会停下来。很多时候,我们都需要自己用 echo $?
或者 ret=$?
来判断上一个命令返回的状态,这就像在代码中判断一个函数的返回值一样。
如果希望改变这种模式,任何命令如果执行失败,整个脚本就停下来,就使用 set -e
。
当然,也有些命令的返回为非0,并不表示失败,这种情况在脚本中,可以这样来处理:
set -e # non-zero stop
command1
command2
set +e # return to default non-zero non-stop
command3
command4
set -e
调试shell脚本必备:
set -uex
!
set -e
的一个例外情况是管道,就算设置了set -e,bash也只会把管道最后一个子命令的返回值,作为整个命令的返回值,因此,如果管道前面的命令执行失败,但是最后的子命令成功,整个命令还是成功,set -e就失效了!
解决这种情况,需要设置 set -o pipefail
。结合-e,在脚本中,可以有这么一行:
set -eo pipefail
命令行功能强大,可以很复杂很长,行编辑功能是long-command-line-life-saver。
默认命令行编辑的快捷键都是emacs风格,用这个命令set -o vi
可以将快捷键设置为vi风格,输入命令按Esc后,对这一行的编辑就如同使用vi。
有人说他特别喜欢b
键功能(按单词向后退),我还喜欢w
键功能(按单词前进),当要修改很长的命令行时,这样的功能非常方便。
上下切换历史命令,也变成了j
和k
。0
移动光标到开始,$
移动光标到末尾。
D
:从光标位置开始,向后删除所有;
d0
:从光标位置开始,向前删除所有;
我有一篇专门收集Vim使用技巧的文章。
当行编辑处于vi模式下的时候,在vi的命令模式下,Ctrl-L
快捷键的效果,有点像clear命令,但这个快捷键不是清除屏幕,而是将当前行顶到最上面,也是清屏的效果,但还可以向上滚动查看历史信息。
切回默认:set -o emacs
set -n
:等同于set -o noexec
,不运行命令,只检查脚本的语法是否正确。
此功能也可以用bash的参数启动:
$ bash -n <script>
删除某个shell变量,不管是环境变量,还是自定义的:unset varName
删除shell函数:unset -f functionName
开启job control,具体请参考:Job Control
-f Disable file name generation (globbing).
关闭命令行的glob功能,或者set -o noglob
。
set positional parameters
用如下方式设置位置参数:
$ set 1 2 a b
$ echo $# $1 $2 $3 $4
4 1 2 a b
unset所有位置参数:
$ echo $# $1 $2 $3 $4
4 1 2 a b
$ set --
$ echo $# $1 $2 $3 $4
0
设置位置参数的同时,关闭-x和-v:$ set - 1 2 3
,不知道有什么用?
本文链接:https://cs.pynote.net/sf/linux/shell/202110305/
-- EOF --
-- MORE --