Shell脚本常见特殊命令用法记录
Shell脚本中常见特殊命令用法记录
1、信号捕获:trap
trap "commands" signals # 接收到signals指定的信号时,执行commands命令。
trap signals # 如果没有指定命令就是恢复 signals的动作。比如 trap INT 就是恢复Ctrl+C。
trap "" signals # 忽略信号signals
trap -l # 列出所有的信号
[root@localhost ~]# trap -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
# shell"伪信号"
信号名 产生时间
EXIT 从一个函数中退出或整个脚本执行完毕
ERR 当一条命令返回非0状态
DEBUG 脚本中每条命令执行之前
# Example:
#!/bin/sh
set -e
lockfile=/tmp/lockfile
[ -f $lockfile ] && echo It is running! && exit 1
function finish()
{
rm -f "$lockfile"
}
touch $lockfile && trap finish EXIT
2、文件路径中获取文件目录:dirname
[root@localhost ~]# dirname /usr/bin/
/usr
[root@localhost ~]# dirname .ssh/
.
# Example:
#!/bin/sh
set -e
CURDIR=$(cd $(dirname $0); pwd)
cd $CURDIR
# 在脚本目录下生成测试文件
echo "hello world" > test.txt
3、从标准输入替换环境变量到标准输出:envsubst
[root@localhost ~]# envsubst
I am $USER,my home directory is $HOME.
I am root,my home directory is /root.
[root@localhost ~]# echo '$HOME'
$HOME
[root@localhost ~]# echo '$HOME' | envsubst
/root
# Example:
#!/bin/sh
set -e
envsubst < /root/envfile" > envfile.out
[root@localhost ~]# cat envfile
I am $USER,my home directory is $HOME.
[root@localhost ~]# cat envfile.out
I am root,my home directory is /root.
4、特殊设备用以提供随机数:random/urandom
# /dev/random 是真随机数生成器,它会消耗熵值来产生随机数,同时在熵耗尽的情况下会阻塞,直到有新的熵生成。
# /dev/urandom 是伪随机数生成器,它根据一个初始的随机种子(这个种子来源就是熵池中的熵)来产生一系列的伪随机数,而并不会在熵耗尽的情况下阻塞。
# linux是根据系统的熵池来产生随机数的。熵池就是系统当前的环境噪音,环境噪音的来源很多,键盘的输入、鼠标的移动、内存的使用、文件的使用量、进程数量等等。当系统的熵不够大的时候,则系统产生的随机数随机效果就不是很好,也就是说更容易被人猜测出来。
# Example:
[root@localhost ~]# random_pwd=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 8)
[root@localhost ~]# echo $random_pwd
DmL3uaPs
[root@localhost ~]# random_pwd=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 8)
[root@localhost ~]# echo $random_pwd
kvBK1xN8
5、创建特殊文件:mknod /mkfifo
[root@localhost ~]# ls -l /dev/vdb
brw-rw---- 1 root disk 252, 16 Dec 15 21:22 /dev/vdb
# 查看/dev/vdb,设备号依次为252、16
[root@localhost ~]# rm -rf /dev/vdb
[root@localhost ~]# ls -l /dev/vdb
ls: 无法访问/dev/vdb: 没有那个文件或目录
# Example:
# mknod创建块设备
[root@localhost ~]# mknod /dev/vdb b 252 16
[root@localhost ~]# ls -l /dev/vdb
brw-rw---- 1 root disk 252, 16 Dec 15 21:22 /dev/vdb
# mknod创建命名管道
[root@localhost ~]# mknod fifofile p
# mkfifo命令创建命名管道
[root@localhost ~]# mkfifo fifofile2
[root@localhost ~]# ls -l fifofile*
prw-r--r-- 1 root root 0 Mar 10 11:04 fifofile
prw-r--r-- 1 root root 0 Mar 10 11:12 fifofile2
6、使用命令替换shell进程与文件描述符操作:exec
# 使用新的进程去代替原来的进程上下文,其进程UID不变,原进程后续的命令将不再执行。
[root@localhost ~]# cat exec.sh
#!/bin/bash
echo "command a"
exec echo "command b"
echo "command c"
[root@localhost ~]# chmod +x exec.sh
[root@localhost ~]# ./exec.sh
command a
command b
# 操作文件描述符
command > filename 把标准输出重定向到一个文件中
command >> filename 把标准输出重定向到一个文件中(追加)
command 1 > fielname 把标准输出重定向到一个文件中
command > filename 2>&1 把标准输出和标准错误一起重定向到一个文件中
command 2 > filename 把标准错误重定向到一个文件中
command 2 >> filename 把标准输出重定向到一个文件中(追加)
command >> filename 2>&1 把标准输出和标准错误一起重定向到一个文件中(追加)
command < filename >filename2 把command命令以filename文件作为标准输入,以filename2文件作为标准输出
command < filename 把command命令以filename文件作为标准输入
command << delimiter 把从标准输入中读入,直至遇到delimiter分界符
command <&m 把文件描述符m作为标准输入
command >&m 把标准输出重定向到文件描述符m中
command &m<&- 关闭文件描述符m
exec 3</tmp/test.txt # 以“只读方式”打开文件/tmp/test.txt,文件描述符对应为3
exec 3>/tmp/test.txt # 以“只写方式”打开文件/tmp/test.txt,文件描述符对应为3
exec 3<>/tmp/test.txt # 以“读写方式”打开文件/tmp/test.txt,文件描述符对应为3
exec 3<&- # 关闭文件描述符3
# Example:
#!/bin/sh
set -e
fifofile=fifo.$(date "+%s.%N")
mkfifo $fifofile
# 持续读取命名管道$fifofile的内容并重定向到日志中
cat $fifofile >> log.$(date "+%Y%m%d%H%M%S") &
# 将标准输出和标准错误重定向到命名管道$fifofile
exec 1>$fifofile 2>&1
echo "hello world"
# 该脚本的目的是将脚本运行中的所有回显(标准输出和标准错误)全部保存到日志文件中
[root@localhost ~]# cat log.20230310115306
hello world
7、目录压栈和出栈:pushd/popd
[root@localhost ~]# pushd /opt
/opt ~
[root@localhost opt]# pushd
~ /opt
[root@localhost opt]# popd
~
[root@localhost ~]# popd
-bash: popd: directory stack empty
# Example:
#!/bin/sh
set -e
# 当前目录压栈
pushd . > /dev/null
cd $(dirname $0)
echo "hello world" > test.txt
# 再次回到当前目录
popd > /dev/null
8、参数扩展的扩展形式
# 默认值/替代值:
${var:-word}:如果var不存在或为空,则返回word,但var的值不会改变。
${var:=word}:如果var不存在或为空,则将word赋值给var并返回word。
${var:+word}:如果var不为空,则返回word,否则返回空字符串。
${var:?message}:如果var不存在或为空,则显示message并退出脚本。
# 字符串长度:
${#var}:返回变量var的长度(即字符串中的字符数)。
# 子字符串提取:
${var:start:length}:从var中提取从start位置开始的长度为length的子字符串。如果省略length,则提取从start到字符串末尾的所有字符。如果start是负数,则表示从字符串末尾开始计数。
# 前缀/后缀去除:
${var#pattern}:从var的开头删除最短匹配pattern的部分。
${var##pattern}:从var的开头删除最长匹配pattern的部分。
${var%pattern}:从var的末尾删除最短匹配pattern的部分。
${var%%pattern}:从var的末尾删除最长匹配pattern的部分。
# 字符串替换:
${var/pattern/string}:将var中第一个匹配pattern的部分替换为string。
${var//pattern/string}:将var中所有匹配pattern的部分替换为string。
# 大小写转换:
${var^}:将var的第一个字母转换为大写。
${var^^}:将var中的所有字母转换为大写。
${var,}:将var的第一个字母转换为小写。
${var,,}:将var中的所有字母转换为小写。
9、Here Document小技巧
#!/bin/bash
boy="Hello, boy!"
cat <<-'EOF'
This is Line 1.
$boy
EOF
# 输出:
This is Line 1.
$boy
# 小提示:
# <<- 是 Here Document 的开始标记,允许使用 Tab 键缩进 Here Document 的结束标记(但不能使用空格缩进)。
# 'EOF' 是 Here Document 的结束标记,单引号表示在此 Here Document 中不进行变量替换和命令替换。
# 如果使用 <<EOF(不带单引号),则 Here Document 中的变量和命令会被替换。
10、与变量有关的命令整理
declare
1. 无选项:声明普通变量(等价于直接赋值,等价于set无选项)
2. -r:声明只读变量(不可修改、不可删除,等价于readonly命令)
3. -i:声明整数型变量(自动进行整数运算,避免字符串解析)
4. -a:声明索引数组变量(普通数组,下标为数字)
5. -A:声明关联数组变量(键值对数组,下标为字符串)
6. -x:声明环境变量(等价于export命令,子进程可继承)
readonly
1. 无选项+变量名=值:直接声明并赋值只读变量(不可修改、不可删除,最常用)
2. 无选项+变量名:将已存在的变量设为只读(保留变量值,添加只读属性)
3. -p:查看所有已定义的只读变量(精准筛选,无冗余)
export
1. 无选项+变量名=值:直接声明并导出环境变量(子进程可继承,最常用,等价于declare -x)
2. 无选项+变量名:将已存在的局部变量导出为环境变量(先定义后导出)
3. -p:查看所有已导出的环境变量(精准筛选,无冗余)
env
1. 无选项:输出所有环境变量(纯键值对格式,日常查看,几乎等价于printenv)
2. -i:启动干净的子Shell(清空当前环境变量,仅保留核心内置变量,实现环境隔离)
3. -u变量名:临时删除指定环境变量后运行命令(不影响当前Shell环境,仅单次有效)
printenv
1. 无选项:输出所有环境变量(纯键值对格式,几乎等价于无选项env,专门用于查看)
2. 无选项+变量名:直接查询单个环境变量的值(无需grep筛选,最便捷,核心优势)
3. 无任何环境变量管理功能(仅专注查看,区别于env)
unset
1. 无选项:删除指定普通变量(包括环境变量,删除后当前进程及子进程均失效)
2. 无选项:删除指定数组(支持删除整个数组,或数组中的单个元素)
3. -f:仅删除指定函数(避免与变量名冲突时误删,精准删除函数)
4. 与set无直接对应关系(set配置Shell模式,需用set+选项取消,而非unset)。
set
1. 无选项:查看所有已定义的变量、函数(等价于declare无选项)
2. 无选项+参数列表:设置/重置位置参数($1、$2、$3...)
3. -u:开启「引用未定义变量即报错」模式(提高脚本健壮性)
4. -e:开启「命令执行失败即终止脚本」模式(容错核心)
5. -x:开启「命令执行跟踪」模式(脚本调试神器)
6. -o:查看/设置Shell运行选项(整合型选项,便捷替代单个选项)
7. 补充实用选项:-n(语法检查,不执行命令)
作者:wanghongwei
版权声明:本作品遵循<CC BY-NC-ND 4.0>版权协议,商业转载请联系作者获得授权,非商业转载请附上原文出处链接及本声明。

浙公网安备 33010602011771号