1.命令作用
设置shell的属性变量,显示当前shell所有变量(包括shell变量、自定义变量、用户变量)
2.命令语法
Usage: set [+/-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
3.参数详解
OPTION:
- -a,启用自动导出模式,此后所有新建或修改的变量会自动标记为环境变量(等效于 export VAR)
- +a,关闭自动导出模式,恢复默认行为(需手动export导出变量)
- -b,后台执行结果执行完直接输出
- +b,后台执行结果执行完需要等待回车或者下一个命令执行才输出(默认)
- -e,脚本运行错误时直接退出
- +e,脚本运行错误会接着后续的程序运行,直到脚本运行完(默认)
- -f/+f,关闭/启动文件名称通配符匹配
- -h/+h,记录函数存储路径,避免重复查找加速后续调用,大型脚本推荐使用以提升性能
- -k/+k,开启参数转环境变量功能
- -m/+m,启用/关闭作业控制的选项
- -n/+n,启动/关闭语法检测,启动参数则不会实际执行命令,关闭参数则实际执行命令
- -p/+p,启动优先顺序模式,shell会以更高优先级执行命令,可能影响系统资源分配
- -t,执行后退出shell
- -u/+u,启动/关闭未定义变量检查选项
- -v/+v,启动/关闭详细模式,启动会在执行时逐行显示原始的命令
- -x/+x,启动/关闭调试模式,启动会在执行时逐行显示执行的命令
- -B/+B,启动/关闭大括号扩展匹配
- -C/+C,关闭/启动重定向覆盖文件,启用>重定向,若目标文件已存在则报错,需使用>|强制覆盖,关闭则使用默认的>重定向
- -H/+H,启用/关闭历史命令扩展匹配,允许通过 ! 符号快速调用或修改历史记录中的命令
- -P/+P,启用/关闭物理路径模式
- -o/+o,查看或设置shell选项
4.常用用例
4.1.启用自动导出模式(设置的变量是环境变量)
[root@node2 ~]# env | grep DB_HOST # 查看没有DB_HOST环境变量
[root@node2 ~]# DB_HOST="localhost" # 设置DB_HOST变量(这里是普通的变量,设置后env里面看不到)
[root@node2 ~]# env | grep DB_HOST # 查看没有DB_HOST用户变量
[root@node2 ~]# set -a
[root@node2 ~]# DB_HOST="localhost"
[root@node2 ~]# env | grep DB_HOST # 在set -a后设置DB_HOST变量是环境变量,env里面可以看到,与export DB_HOST="localhost" 效果一样
DB_HOST=localhost
[root@node2 ~]# set +a # 关闭后恢复默认,设置的变量是普通变量
[root@node2 ~]# env | grep DB_HOST
DB_HOST=localhost
[root@node2 ~]#
4.2.控制后台命令执行输出效果
[root@node1 ~]# set -b
[root@node1 ~]# sleep 5 & # 指定set -b后,后台执行完后直接输出结果
[1] 33954
[root@node1 ~]# [1]+ Done sleep 5
[root@node1 ~]# set +b # 指定set +b后,后台执行完后需要回车或者执行下一个命令才输出执行结果(默认效果)
[root@node1 ~]# sleep 5 &
[1] 33955
[root@node1 ~]#
[1]+ Done sleep 5
[root@node1 ~]#
4.3.shell脚本开启错误直接退出
[root@node1 ~]# cat test.sh
#!/bin/bash
set -e # 开启错误退出
mkdir /tmp/example/dir1 # 如果/tmp/example不存在,则创建该目录会失败
cd /tmp/example/dir1
echo "execution is completed"
set +e # 关闭错误退出
[root@node1 ~]# sh test.sh # 执行到创建目录失败就直接退出,不会输出execution is completed
mkdir: cannot create directory ‘/tmp/example/dir1’: No such file or directory
[root@node1 ~]#
4.4.关闭文件名通配符
[root@node1 ~]# set -f # 关闭文件名通配符扩展,*txt会当成普通字符
[root@node1 ~]# echo *txt
*txt
[root@node1 ~]# set +f # 开启文件名通配符扩展,*txt通配匹配所有txt结尾的文件
[root@node1 ~]# echo *txt
test.txt
[root@node1 ~]#
4.5.启停作业控制的选项
# 命令解释:
sleep 100 & # 任务1 后台运行
sleep 120 & # 任务2 后台运行
jobs # 查看任务编号(如 [1], [2])
fg %2 # 将任务2 提到前台,可以执行Ctrl+Z暂停前台任务并保留到后台
bg %2 # 将暂停的任务转为后台运行
kill %2 # 终止指定编号的后台任务
# 测试用例:
[root@node1 ~]# set -m # 默认,启动管理jobs后台任务
[root@node1 ~]# sleep 100 &
[1] 37813
[root@node1 ~]# sleep 120 &
[2] 37814
[root@node1 ~]# jobs
[1]- Running sleep 100 &
[2]+ Running sleep 120 &
[root@node1 ~]# fg %2
sleep 120
^Z
[2]+ Stopped sleep 120
[root@node1 ~]# jobs
[1]- Running sleep 100 &
[2]+ Stopped sleep 120
[root@node1 ~]# bg %2
[2]+ sleep 120 &
[root@node1 ~]# jobs
[1]- Running sleep 100 &
[2]+ Running sleep 120 &
[root@node1 ~]# kill %2
[root@node1 ~]# jobs
[1]- Running sleep 100 &
[2]+ Terminated sleep 120
[root@node1 ~]# jobs
[1]+ Running sleep 100 &
[root@node1 ~]#
[root@node1 ~]# set +m # 关闭jobs后台任务的管理
[root@node1 ~]# sleep 100 &
[1] 37849
[root@node1 ~]# sleep 120 &
[2] 37850
[root@node1 ~]# jobs
[1]- Running sleep 100 &
[2]+ Running sleep 120 &
[root@node1 ~]# fg %2 # 设置set +m后,后台任务管理会报错
-bash: fg: no job control
[root@node1 ~]#
4.6.启动语法检测并不实际执行
[root@node1 ~]# cat test1.sh
#!/bin/bash
set -n # 启动语法检测,读取脚本命令并检查语法错误,但不执行任何实际命令
mkdir -p /tmp/example/dir1
cd /tmp/example/dir1
echo "execution is completed"
set +n # 关闭语法检测,关闭后执行就是实际执行
[root@node1 ~]# sh test1.sh # 其中有-n参数,所以实际并不执行任何命令
[root@node1 ~]# ll /tmp/example/dir1 # 实际并不执行,所以目录不存在
ls: cannot access /tmp/example/dir1: No such file or directory
[root@node1 ~]#
4.7.对未定义变量进行检查
[root@node1 ~]# echo $UNDEFINED_VAR
[root@node1 ~]# set -u
[root@node1 ~]# echo $UNDEFINED_VAR
-bash: UNDEFINED_VAR: unbound variable
[root@node1 ~]#
4.8.启动详细模式
[root@node1 ~]# cat test2.sh
#!/bin/bash
set -v
name="zhangsan"
echo "Hello, $name"
set +v
[root@node1 ~]# sh test2.sh
name="zhangsan"
echo "Hello, $name"
Hello, zhangsan
set +v
[root@node1 ~]#
4.9.启动调试模式
[root@node1 ~]# cat test3.sh
#!/bin/bash
set -x
name="zhangsan"
echo "Hello, $name"
set +x
[root@node1 ~]# sh test3.sh
+ name=zhangsan
+ echo 'Hello, zhangsan'
Hello, zhangsan
+ set +x
[root@node1 ~]#
4.10.启停大括号扩展匹配
[root@node1 ~]# set -B # 启用大括号扩展匹配
[root@node1 ~]# echo file_{A,B,C}.txt
file_A.txt file_B.txt file_C.txt
[root@node1 ~]# echo {1..3}-item
1-item 2-item 3-item
[root@node1 ~]#
[root@node1 ~]# set +B # 关闭大括号扩展匹配
[root@node1 ~]# echo file_{A,B,C}.txt
file_{A,B,C}.txt
[root@node1 ~]# echo {1..3}-item
{1..3}-item
[root@node1 ~]#
4.11.启停重定向覆盖文件
[root@node1 ~]# set -C
[root@node1 ~]# echo 'This is new content' > exist.txt
[root@node1 ~]# echo 'This is new content' > exist.txt
-bash: exist.txt: cannot overwrite existing file
[root@node1 ~]# echo 'This is new content' >| exist.txt
[root@node1 ~]# set +C
[root@node1 ~]# echo 'This is new content' > exist.txt
[root@node1 ~]#
4.12.启停历史命令扩展匹配
# 执行history中的历史命令
[root@node1 ~]# history | grep 1026
1026 ll test.sh
1047 history | grep 1026
[root@node1 ~]# !1026 # 执行history中id为1026的命令
ll test.sh
-rw-r--r--. 1 root root 187 Jun 11 18:22 test.sh
[root@node1 ~]# !! # 执行上一个命令,即history中最后一个命令
ll test.sh
-rw-r--r--. 1 root root 187 Jun 11 18:22 test.sh
[root@node1 ~]# !ll # 执行最后一个带有ll的参数
ll test.sh
-rw-r--r--. 1 root root 187 Jun 11 18:22 test.sh
[root@node1 ~]#
# 启停历史命令扩展匹配
[root@node1 ~]# set -H
[root@node1 ~]# ll test.sh test1.sh
-rwxr-xr-x. 1 root root 190 Jun 11 20:36 test1.sh
-rw-r--r--. 1 root root 187 Jun 11 18:22 test.sh
[root@node1 ~]# chmod 755 !$
chmod 755 test1.sh
[root@node1 ~]# set +H
[root@node1 ~]# ll test.sh test1.sh
-rwxr-xr-x. 1 root root 190 Jun 11 20:36 test1.sh
-rw-r--r--. 1 root root 187 Jun 11 18:22 test.sh
[root@node1 ~]# chmod 755 !$
chmod: cannot access ‘!$’: No such file or directory
[root@node1 ~]#
说明:
!^,读取上一个命令第一个参数值,ll是命令,第一个参数是test.txt
!$,读取上一个命令最后一个参数值,ll是命令,第二个参数是test1.txt
!:2,读取上一个命令第二个参数值
!:0,是命令名,命令参数是从1开始
4.13.启停物理路径模式
set -P # 启用物理路径模式
cp /opt/link_to_config /backup/ # 复制实际文件而非符号链接
set +P # 关闭物理路径模式
ls /usr/bin/python* # 快速读取缓存路径,加速重复命令
4.14.查看或设置shell选项
set -o # 列出所有shell选项及其开关状态,on为启用,off为关闭
set -o 选项名 # 启用选项
set +o 选项名 # 关闭选项
4.15.其他
set -o errexit # 同set -e,命令失败时退出
set -o nounset # 同set -u,未定义变量时报错
set -o xtrace # 同set -x,启动调试模式
set -o pipefail # 管道错误检测
[root@node1 ~]# set -o pipefail # 启动后,管道符前后所有命令必须都成功才算成功
[root@node1 ~]# true | true
[root@node1 ~]# echo $?
0
[root@node1 ~]# false | true
[root@node1 ~]# echo $?
1
[root@node1 ~]# true | false
[root@node1 ~]# echo $?
1
[root@node1 ~]# false | false
[root@node1 ~]# echo $?
1
[root@node1 ~]#
[root@node1 ~]#
[root@node1 ~]# set +o pipefail # 未启动时,仅管道符最后一个命令成功才算成功(默认参数)
[root@node1 ~]# true | true
[root@node1 ~]# echo $?
0
[root@node1 ~]# false | true
[root@node1 ~]# echo $?
0
[root@node1 ~]# true | false
[root@node1 ~]# echo $?
1
[root@node1 ~]# false | false
[root@node1 ~]# echo $?
1
[root@node1 ~]#