参见:
http://www.ruanyifeng.com/blog/2017/11/bash-set.html
Bash 执行脚本的时候,会创建一个新的 Shell。
# bash
script.sh
上面代码中,
script.sh
是在一个新的 Shell 里面执行。这个 Shell 就是脚本的执行环境,Bash 默认给定了这个环境的各种参数。
set
命令用来修改 Shell 环境的运行参数,也就是可以定制环境。一共有十几个参数可以定制,
官方手册
有完整清单,本文介绍其中最常用的四个。顺便提一下,如果命令行下不带任何参数,直接运行
set
,会显示所有的环境变量和 Shell 函数。
set -e
如果脚本里面有运行失败的命令(返回值非0),Bash 默认会继续执行后面的命令。
#!/usr/bin/env bash
foo
echo bar
上面脚本中,foo是一个不存在的命令,执行时会报错。但是,Bash 会忽略这个错误,继续往下执行。
$ bash script.sh
script.sh:行3: foo: 未找到命令
bar
可以看到,Bash 只是显示有错误,并没有终止执行。
这种行为很不利于脚本安全和除错。实际开发中,如果某个命令失败,往往需要脚本停止执行,防止错误累积。这时,一般采用下面的写法。
command || exit 1
上面的写法表示只要command有非零返回值,脚本就会停止执行。
如果停止执行之前需要完成多个操作,就要采用下面三种写法。
# 写法一
command || { echo "command failed"; exit 1; }
# 写法二
if ! command; then echo "command failed"; exit 1; fi
# 写法三
command
if [ "$?" -ne 0 ]; then echo "command failed"; exit 1; fi
另外,除了停止执行,还有一种情况。如果两个命令有继承关系,只有第一个命令成功了,才能继续执行第二个命令,那么就要采用下面的写法。
command1 && command2
上面这些写法多少有些麻烦,容易疏忽。set -e从根本上解决了这个问题,它使得脚本只要发生错误,就终止执行。
#!/usr/bin/env bash
set -e
foo
echo bar
set +e表示关闭-e选项,
set -e表示重新打开-e选项。
还有一种方法是使用command || true,使得该命令即使执行失败,脚本也不会终止执行。
#!/bin/bash
set -e
foo || true
echo bar
上面代码中,true使得这一行语句总是会执行成功,后面的echo bar会执行。
set -o pipefail
set -e有一个例外情况,就是不适用于管道命令。
所谓管道命令,就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e就失效了。
请看下面这个例子。
#!/usr/bin/env bash
set -e
foo | echo a
echo bar
执行结果如下。
$ bash script.sh
a
script.sh:行4: foo: 未找到命令
bar
上面代码中,foo是一个不存在的命令,但是foo | echo a这个管道命令会执行成功,导致后面的echo bar会继续执行。
set -o pipefail用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行。
#!/usr/bin/env bash
set -eo pipefail
foo | echo a
echo bar
运行后,结果如下。
$ bash script.sh
a
script.sh:行4: foo: 未找到命令
set -u
执行脚本的时候,如果遇到不存在的变量,Bash 默认忽略它。
#!/usr/bin/env bash
echo $a
echo bar
上面代码中,$a是一个不存在的变量。执行结果如下。
$ bash script.sh
bar
可以看到,echo $a输出了一个空行,Bash 忽略了不存在的$a,然后继续执行echo bar。大多数情况下,这不是开发者想要的行为,遇到变量不存在,脚本应该报错,而不是一声不响地往下执行。
set -u就用来改变这种行为。脚本在头部加上它,遇到不存在的变量就会报错,并停止执行。
#!/usr/bin/env bash
set -u
echo $a
echo bar
-u还有另一种写法-o nounset,两者是等价的。
set -o nounset
set -x
默认情况下,脚本执行后,屏幕只显示运行结果,没有其他内容。如果多个命令连续执行,它们的运行结果就会连续输出。有时会分不清,某一段内容是什么命令产生的。set -x用来在运行结果之前,先输出执行的那一行命令。
set -x 开始调试;
set +x 结束调试;
-x还有另一种写法-o xtrace。
set -o xtrace
退出状态如果找到选定的行,则退出状态为0,如果找不到,则为1。如果发生错误,则退出状态为2。(注:POSIX错误处理代码应检查'2'或更大。)
如果您想将退出代码强制设置为0,则只需将
|| true
附加到命令中即可:
echo 'Total' | grep -c No || true
-c,--count禁止正常输出;而是为每个输入文件打印匹配行数。
因此,您所看到的是匹配项的计数,不要与grep匹配项的退出代码混淆
grep -c "xx" 文件 <=====> grep "xxx" 文件 | wc -l
grep范例
echo 'Total' | grep -c No
0
因此,“总计”中不存在“否”。但是然后查找其返回码,
echo $?
1
echo 'No' | grep -c No
1
echo $?
0
#! /bin/bash
set -x
set -o pipefail
local mlnx_enabled=$(lspci -s "0000:5e:00.0" | grep -ci "Mellanox")
if [[ ${mlnx_enabled} -ne 0 ]]; then
echo "Mellanox nic enabled"
echo "Mellanox nic not enable"
对于在非Mellanox nic 的机器上,上诉代码会直接退出,而不会输出任何 echo 信息。
因为 grep -ci "Mellanox" 的 输出值为 0,退出码为 1;
由于退出码为1,即异常退出,此时 set -e 被设置,则会执行到 mlnx_enabled=$(lspci -s "0000:5e:00.0" | grep -ci "Mellanox")
时,程序直接退出;
#! /bin/bash
set -x
set -o pipefail
local mlnx_enabled=$(lspci -s "0000:5e:00.0" | grep -i "Mellanox" | wc -l)
if [[ ${mlnx_enabled} -ne 0 ]]; then
echo "Mellanox nic enabled"
echo "Mellanox nic not enable"
grep -i "Mellanox" 的退出码为1,但是 grep -i "Mellanox" | wc -l 整体的退出码其实是 wc -l 的退出码,不为1,所以不会由于 set -e 而退出。
但是由于 set -o pipefail 的存在,管道的任何一个子命令失败,都会退出。由于 grep -i "Mellanox" 失败,从而导致程序退出。
失败cmd && 或者 失败cmd || 就可以让 set -e 失效;
# cat test.sh
#!/usr/bin/env bash
set -e
set -o pipefail
echo "test1"
MELLANOX="FALSE"
lspci -s "0000:5e:00.0" | grep -ci "222Mellanox" && MELLANOX="true"
echo "$?"
echo "MELLANOX: ${MELLANOX}"
echo "test2"
MELLANOX="FALSE"
lspci -s "0000:5e:00.0" | grep -ci "Mellanox" && MELLANOX="true"
echo "$?"
echo "MELLANOX: ${MELLANOX}"
echo "test3"
MELLANOX="FALSE"
lspci -s "0000:5e:00.0" | grep -ci "2222Mellanox"
if [[ $? -eq 0 ]]; then
MELLANOX="true"
fi
echo "MELLANOX: ${MELLANOX}"
# sh -x test.sh
+ set -e
+ set -o pipefail
+ echo test1
test1
+ MELLANOX=FALSE
+ lspci -s 0000:5e:00.0
+ grep -ci 222Mellanox
0
+ echo 1
1
+ echo 'MELLANOX: FALSE'
MELLANOX: FALSE
+ echo test2
test2
+ MELLANOX=FALSE
+ lspci -s 0000:5e:00.0
+ grep -ci Mellanox
1
+ MELLANOX=true
+ echo 0
0
+ echo 'MELLANOX: true'
MELLANOX: true
+ echo test3
test3
+ MELLANOX=FALSE
+ lspci -s 0000:5e:00.0
+ grep -ci 2222Mellanox
0
原文链接:
http://www.ruanyifeng.com/blog/2017/11/bash-set.html
-C:转向所产生的文件无法覆盖已存在的文件
-d:
Shell
预设会用杂凑表记忆使用过的指令,以加速指令的执行。使用-d参数可取消
-e:若指令传回值不等于0,则立即
退出
shell
-f:取消使用通配符
-h:自动记录函数的所在位置
-k:指令所给的参数都会被视为此指令的环境变量
-l:记录for循环的变量名称
-m:使用监视模式
当一行命令
中
包含多个子命令时,
set
-e选项只会检查整行命令的
退出
状态。如果整行命令的
退出
状态为非零,表示整行命令执行失败,
shell
会立即
退出
脚本。是 Linux
shell
中
的一个选项,它的作用是在脚本执行过程
中
,一旦出现任何命令执行失败(返回非零的
退出
状态码),脚本就会立即
退出
。然后,继续执行后续的。是一个命令,它总是返回真(即
退出
状态为0),所以无论前面子命令是否执行成功,是逻辑或运算符,它的作用是在前一个命令执行失败时执行后面的命令。的返回值不为0,那么整个表达式的返回值为0,脚本不会
退出
。
$ bash script.sh
上面代码
中
,script.sh是在一个新的
Shell
里面执行。这个
Shell
就是脚本的执行环境,Bash 默认给定了这个环境的各种参数。
set
命令用来修改
Shell
环境的运行参数,也就是可以定制环境。一共有十几个参数可以定制,官方手册有完整清单,本文介绍其
中
最常用的四个。
1)...
文章目录1. 简介2.
set
-e3.
set
-o pipefail4.
set
-u5.
set
-x6. 总结
1. 简介
在写
shell
的时候我们经常面临的
问题
就是
shell
遇到错误的时候不会停止,接着执行下面的
shell
命令的时候有时候是一种非预期的行为,可能会产生破坏性,所以我们写的总是小心翼翼。
同时,
shell
的调试比较困难,尤其是当我们在linux服务器上使用vim来进行
shell
的编写的时候更会存在这种情况,只能靠不断的加一些echo命令来尝试看看发生了什么。
这里会介绍
shell
编写
shell
脚本没多久,对于其许多命令的具体用法还不太熟悉。最近刚好有需求,就尝试用脚本去实现。其
中
就有用到
set
-e选项。
在用这个命令之前,也查过其功能,描述比较简单:就是当命令以非零状态
退出
时,则
退出
shell
。主要作用是,当脚本执行出现意料之外的情况时,立即
退出
,避免错误被忽略,
导致
最终结果不正确。这里主要讨论的是
set
-e 选项的作用范围,创建如下测试文件:
zheng
shell
中
脚本运行
中
可能出现命令执行失败的情况,如果执行失败对后续有影响那么就应该
退出
脚本,不继续往下执行。
set
-e 命令就可以避免操作失败还继续往下执行的
问题
。
set
命令的-e参数:
linux系统自带的说明是:“Exit immediately if a simple command exits with a non-zero status.”,也就是说,在"
set
-e"之后出现的代码,一旦出现了返回值非零,整个脚本就会立即
退出
set
指令可根据不同的需求来设置当前所使用
shell
的执行方式,同时也可以用来设置或显示
shell
变量的值。当指定某个单一的选项时将设置
shell
的常用特性,如果在选项后使用 -o 参数将打开特殊特性,若是 +o 将关闭相应的特殊特性。而不带任何参数的
set
指令将显示当前
shell
中
的全部变量,且总是返回 true,除非遇到非法的选项。
Linux
shell
脚本内的
set
-x
set
+x
set
-e
set
-u
set
-n的应用
set
命令可以定义脚本的运行方式,变量的获取方式,脚本的执行过程,脚本的测试。
1,
set
-u (检查脚本内的变量,如果有变量未被定义将终止脚本)(脚本的自检测功能)
#!/bin/bash
set
-u
echo $A
这是一个极为简单的
shell
脚本,功能为输出变量abc的值,但可以看到在脚本内并没有给定变...
"Exit immediately if a simple command exits with a non-zero status."
也就是说,在"
set
-e"之后出现的代码,一旦出现了返回值非零,整个脚本就会立即
退出
。
#!/bin/bash
set
-e
ls a.txt | echo "hi" >/dev/null
echo $?
echo "test"
执行结果:
没有a.txt文件,但是ls a.txt | echo “hi” >/dev/n