添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

参见: 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