当前位置:   article > 正文

shell脚本命令set_shell set

shell set

1. 简介

在写shell的时候我们经常面临的问题一般都是:

  1. shell遇到错误的时候不会停止,接着执行下面的shell命令的时候有时候是一种非预期的行为,可能会产生破坏性,所以我们写的总是小心翼翼。
  2. shell的调试比较困难,尤其是当我们在linux服务器上使用vim来进行shell的编写的时候更会存在这种情况,只能靠不断的加一些echo命令来尝试看看发生了什么。

这里会介绍shell脚本中的一个非常有用的命令,上面的错误可以通过这个命令来避免,脚本的调试也会变得非常容易,这个牛叉的命令就是set命令。

set 命令在没有参数的时候会显示当前环境的所有环境变量,比如直接执行 set 看一看到一大堆东西

set

  • 1
  • 2

带参数的命令可以用来设置shell的变量,他的功能还挺多的,今天我们主要学习的是和shell脚本的运行模式有关的命令,主要的命令有以下几个。

set -e
set +e

set -u
set +u

set -x
set +x

set -o pipefail
set +o pipefail

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以看到上面的命令基本都是成对出现的,一个是减号,一个是加号,我们可以理解为set命令是对shell的工作模式进行了设置
减号- 是开启了某种模式,加号 + 则是关闭对应的模式。后面我们会详细介绍。

2. set -e

set -e的功能是遇到错误后脚本会直接退出,不会继续往下执行
我们先准备一个脚本 test.sh

cat test.sh
#!/bin/bash

aa=123
cat $aa
necho $aa
echo $aa

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

执行bash test.sh

cat: 123: No such file or directory
test.sh: line 5: necho: command not found
123

  • 1
  • 2
  • 3
  • 4

因为不存在名子为123的文件,所以cat命令执行报错,同样的,因为不存在necho命令,所以也会报错,关键是报错后都会继续向下执行,所以

echo $aa

  • 1
  • 2

还是会成功输出123, 但是很多时候我们希望在执行错误后能够立即退出,而不是继续向下执行,那么可以在代码前加一个set -e

$ cat test.sh

#!/bin/bash

set -e
aa=123
cat $aa
necho $aa
echo $aa

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

$ bash test.sh

cat: 123: No such file or directory

  • 1
  • 2

这样就ok了,遇到错误后脚本会直接退出,不会继续往下执行。
如果你只是想对其中的一段代码做这种的设置,那么你可以这样做

$ cat -n test.sh
     1	#!/bin/bash
     2
     3	aa=123
     4	cat $aa
     5	set -e
     6	echo $aa
     7	set +e
     8	necho $aa
     9	echo $aa

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行

$ bash test.sh
cat: 123: No such file or directory
123
test.sh: line 8: necho: command not found
123
  • 1
  • 2
  • 3
  • 4
  • 5

对于上面的文件set的作用域只是在第5-7行,因为第6行可以正确执行,所以整个脚本也就可以正确执行了。
这种局部开启的方式很多时候没有必要,尽量在文件头部加一个就好了,当然在有些时候还是很有必要的,比如你要判断某个子shell的执行结果,使用了$? 变量,那么就要关闭set了。

3. set -o pipefail

set -o pipefail这个命令主要是对上面的set -e 的补充,因为set -e 对于管道符是无效的,比如上面的脚本假如变成

$ cat -n test.sh
     1	#!/bin/bash
     2
     3	set -e
     4	aa=123
     5	cat $aa | echo
     6	echo $aa
     7
     8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

执行

$ bash test.sh

cat: 123: No such file or directory
123

  • 1
  • 2
  • 3
  • 4
  • 5

可以看到使用管道符号| 的话set -e 也不好用了,这个时候假如使用 set -o pipefail 则可以解决这个问题

$ cat -n test.sh
     1	#!/bin/bash
     2
     3	set -e
     4	set -o pipefail
     5
     6	aa=123
     7	cat $aa | echo
     8	echo $aa
     9
    10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行

$ bash test.sh

cat: 123: No such file or directory
  • 1
  • 2
  • 3

可以看到cat失败后后面的不会再执行了。

4. set -u

执行脚本的时候,如果遇到不存在的变量,Bash 默认忽略它,set -u 可以在需要的变量不存在的时候直接报错退出

 cat -n test.sh
     1	#!/bin/bash
     2
     3	aa=123
     4	echo $bb
     5	echo $aa

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

执行

$ bash test.sh

123
  • 1
  • 2
  • 3

可以看到,即使变量 bb不存在也不会报错,如果想要避免这种情况,可以这样做

$ cat -n test.sh
     1	#!/bin/bash
     2
     3	set -u
     4	aa=123
     5	echo $bb
     6	echo $aa
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

执行

$ bash test.sh
test.sh: line 5: bb: unbound variable

  • 1
  • 2
  • 3

同样的,你也可以通过

set +u
  • 1

关闭这个模式设置

5. set -x

  有些时候我们写的脚本比价长也比较复杂,引起最终结果出错的原因可能是前面多个步骤运算出错导致的(程序没有语法错误,可能是赋值计算等出错)
  这个时候如果通过echo的方式去调试每一步的值会非常麻烦,而且后面还要注释掉大量的echo语句。这个时候就可以通过set -x 来打开调试,让调试变得十分简单。


$ cat -n test.sh
     1	#!/bin/bash
     2
     3
     4	ip=`ifconfig eth0| awk  'NR==2{print $0}'|awk -F "[:]" '{print $2}'|awk '{print $1}'`
     5	set -x
     6	k=$ip"aaa"
     7	set +x
     8	echo "$k"
     9
    10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

执行


$ bash test.sh
+ k=10.76.0.27aaa
+ set +x
10.76.0.27aaa

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

要是能够显示哪一行执行的结果就更好了,别怕,可以这样设置

$ cat -n test.sh
     1	#!/bin/bash
     2
     3	export PS4='+{$LINENO:${FUNCNAME[0]}} '
     4
     5	ip=`ifconfig eth0| awk  'NR==2{print $0}'|awk -F "[:]" '{print $2}'|awk '{print $1}'`
     6	set -x
     7	k=$ip"aaa"
     8	set +x
     9	echo "$k"
    10
    11

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

再执行

$ bash test.sh
+{7:} k=10.76.0.27aaa
+{8:} set +x
10.76.0.27aaa

  • 1
  • 2
  • 3
  • 4
  • 5

可以看到行号也显示出来了,其实冒号后面是要显示方法名的,因为这里没有使用方法,所以没有显示。下面给一个方法使用的样例。

$ cat -n test.sh
     1	#!/bin/bash
     2
     3	export PS4='+{$LINENO:${FUNCNAME[0]}} '
     4
     5
     6	function tool()
     7	{
     8
     9	ip=`ifconfig eth0| awk  'NR==2{print $0}'|awk -F "[:]" '{print $2}'|awk '{print $1}'`
    10	set -x
    11	k=$ip"aaa"
    12	set +x
    13	echo "$k"
    14
    15	}
    16
    17	tool
    18

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

执行

$ bash test.sh
+{11:tool} k=10.76.0.27aaa
+{12:tool} set +x
10.76.0.27aaa

  • 1
  • 2
  • 3
  • 4
  • 5

6. 总结

  通过上面的样例学习,可以了解到使用set命令可以使我们的shell变得更加安全,可预期。同时别忘了,set + 是可以关闭对应的模式的,这个在有些时候也是有必要的。
  对于初开始写shell脚本的同学可以养成使用这个命令的习惯,会大大提升shell编写的安全感。
建议

set -e
set -u
set -o pipefail
  • 1
  • 2
  • 3

都直接开启
对于复杂的脚本可以局部开启

set -x

  • 1
  • 2
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/881876
推荐阅读
相关标签
  

闽ICP备14008679号