博文记录了一些实用 Shell 指令,以备不时之需。
1. 几种特殊的替换用法
若变量为空,则用默认值执行${var:-string}1 2 3 4 5 6 7 # !/bin/bash var= echo ${var:-NULL} echo $var # 执行结果如下: NULL
若变量为空,则用默认值赋值给空变量${var:=abc}1 2 3 4 5 6 7 # !/bin/bash var= echo ${var:=abc} echo $var # 执行结果如下: abc
若变量非空,则用默认值执行,若变量为空,则不作为${var:+string}1 2 3 4 5 6 7 8 # !/bin/bash var1=abc var2= echo ${var1:+FULL} echo ${var2:+FULL} # 执行结果如下: FULL
若变量非空,则用其值,若变量为空,则输出 string 到标准错误中后退出脚本${var:?string}1 2 3 4 5 6 7 8 # !/bin/bash var1=abc var2= echo ${var1:+FULL} echo ${var2:+FULL} # 执行结果如下: FULL
2. 支持 POSIX 标准的扩展计算
其中 exp 为符合 C 语言的运算符,示例如下
1 2 3 4 5 6 7 8 9 10 11 # !/bin/bash echo $((1+2)) echo $((1<2)) echo $((5<4?0:1)) echo $((var=2+3)) echo $((var++)) # 执行结果如下: 3 1 5 6
3. 四种模式匹配替换
# 是去掉左边(在键盘上、#在、$之左边);
% 是去掉右边(在键盘上、%在、$之右边);
#和、%中的单一符号是最小匹配,两个相同符号是最大匹配。
这四种模式中都不会改变 variable 的值,其中,只有在 pattern 中使用了、*匹配符号时,%和%%,#和##才有区别。
结构中的 pattern 支持通配符:
*表示零个或多个任意字符
? 表示仅与一个任意字符匹配
[…] 表示匹配中括号里面的字符
[!…] 表示不匹配中括号里面的字符
模式 1:${variable%pattern}
说明:shell 在 variable 中查找,判断 variable 是否以 pattern 结尾,如果是,就从命令行把 variable 中的内容去掉右边最短的 匹配模式
模式 2:${variable%%pattern}
说明:shell 在 variable 中查找,判断 variable 是否以 pattern 结尾,如果是,就从命令行把 variable 中的内容去掉右边最长的 匹配模式
模式 3:${variable#pattern}
说明:shell 在 variable 中查找,判断 variable 是否以 pattern 开始,如果是,就从命令行把 variable 中的内容去掉左边最短的匹配模式
模式 4:${variable##pattern}
shell 在 variable 中查找,判断 variable 是否以 pattern 开始,如果是,就从命令行把 variable 中的内容去掉右边最长的匹配模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # !/bin/bash VAR=ABCABCDEFDEF PATTERN1=DEF PATTERN2=ABC echo "VAR=$VAR" echo "PATTERN1=$PATTERN1" echo "PATTERN2=$PATTERN2" echo 'M1.${VAR%*$PATTERN1}' echo ${VAR%*$PATTERN1} echo 'M2.${VAR%%*$PATTERN1}' echo ${VAR%%*$PATTERN1} echo 'M2.${VAR%%?$PATTERN1}' echo ${VAR%%?$PATTERN1} echo 'M3.${VAR#*$PATTERN2}' echo ${VAR#*$PATTERN2} echo 'M4.${VAR##*$PATTERN2}' echo ${VAR##*$PATTERN2} echo 'M4.${VAR##$PATTERN2*}' echo ${VAR##$PATTERN2*} # 执行结果 VAR=ABCABCDEFDEF PATTERN1=DEF PATTERN2=ABC M1.${VAR%*$PATTERN1} ABCABCDEF M2.${VAR%%*$PATTERN1} (空) M2.${VAR%%?$PATTERN1} ABCABCDE M3.${VAR#*$PATTERN2} ABCDEFDEF M4.${VAR##*$PATTERN2} DEFDEF M4.${VAR##$PATTERN2*} (空)
4. 变量判空
判空必要性:某些环境下执行空变量可能造成严重后果,如执行 rm 删除操作时,rm -rf 空路径变量会删除根目录,造成无法挽回的严重后果。
正确操作:1 2 3 # !/bin/bash # 判断 DIR 变量非空,才会执行 rm 命令 [ -n $DIR ] && rm -rf $DIR
变量判空常用方法1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # !/bin/bash para= # 判空方式 1. 直接判断变量 if [ ! $para ];then echo "NULL" fi # 判空方式 2. 作字符串判空 if [ ! -n "$para" ];then echo "NULL" fi # 判空方式 3. 与“空字符串”比较判空 if [ "$para" = "" ];then echo "NULL" fi # 判空方式 4. 利用 test 判空 if test -z "$para" then echo "NULL" fi
5. Shell 字符分割 1 tmux a -t $(tmux ls | grep build2021 | awk '{ print $1 }' | cut -d \: -f 1)
6. shell 字符变量切分 1 2 3 str1="I am chinese" # 根据空格分割为数组 array1=(${str1// / })
7. 获取字符串变量长度 1 STR='hello'; echo ${#STR}
8. 字符串截取 8.1. 头部截取(最大 -* 匹配) 从右往左匹配最后遇到的’-‘字符及之后的部分(减掉表达式”-*”最大匹配的部分”-serial-14210”),结果:”/dev/tty.usb”
1 STR="/dev/tty.usb-serial-14210"; echo ${STR%%-*}
8.2. 头部截取(最小 -* 匹配) 从右往左匹配最先遇到的’-‘字符及之后的部分(减掉表达式”-*”最大匹配的部分”-14210”),结果:”/dev/tty.usb-serial” 最后一个’-‘之前的部分,结果:”/dev/tty.usb-serial”
1 STR="/dev/tty.usb-serial-14210"; echo ${STR%-*}
8.3. 尾部截取( *- 最大匹配) 从左往右匹配最后遇到的’-‘字符及之前的部分(减掉表达式”*-“最大匹配的部分”/dev/tty.usb-serial-“),结果:”14210”
1 STR="/dev/tty.usb-serial-14210"; echo ${STR##*-}
8.4. 尾部截取( *- 最小匹配) 从左往右匹配最先遇到的’-‘字符及之前的部分(减掉表达式”*-“最小匹配的部分”/dev/tty.usb-“),结果:”serial-14210”
1 STR="/dev/tty.usb-serial-14210"; echo ${STR#*-}
8.5. cut 截取命令 (以截取 ip “192.168.3.35/24”中’/‘字符前部为例) 1 ip addr | grep 'eth0' | awk '{ print $2 }' | cut -d / -f 1
9. 变量转大小写 1 2 3 4 5 6 7 8 9 str='HelLo World' # 变量转换为大写 upper_str=${str^^} upper_str=$(echo "$str" | tr [a-z] [A-Z]) upper_str=$(echo "$str" | tr [:lower:] [:upper:]) # 变量转换为小写 lower_str=${str,,} lower_str=$(echo "$str" | tr [A-Z] [a-z]) lower_str=$(echo "$str" | tr [:upper:] [:lower:])
10. 输出内容的 字符替换 & 字符删除 1 2 3 4 5 6 7 8 # 替换 echo 'ABCDABCD' | sed 's/ABC/DEF/g' # tr 替换,注意是字符集合替换 echo 'ABCDABCD' | tr 'AD' 'C' # 删除 echo 'ABCDABCD' | sed 's/ABC//g' echo 'ABCDABCD' | tr -d 'AC'
11. 显示文件列表 1 ls -l -A --color=auto --group-directories-first /var/log/
12. 查看个人进程 1 ps -ef |grep lih |fgrep -v vscode | fgrep -v baas
13. 查找文件(过滤无效信息) 1 sudo find / -name "makefile" -print 2>&1 | fgrep -v "Operation not permitted" | fgrep -v "No such file"
14. 统计第 2 列总类型 1 2 3 command | awk '{ print $2 }' | uniq | sort | uniq cat ~/1.txt | awk '{ for(i=2;i<=NF;i++) printf $i""FS;print "" }' | uniq | sort | uniq
15. 只打印 第 n~最末 列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 cat xxx.log | awk '{ for(i=1; i<=3; i++){ $i="" }; print $0 }' ``` # 16. grep 查找命令说明 ```shell -r 是递归查找 -n 是显示行号 -R 查找所有文件包含子目录 -i 忽略大小写 # 增加显示匹配行的 前后各 [number] 行 grep -C number pattern files # 增加显示匹配行的 前的 [number] 行 grep -B number pattern files # 增加显示匹配行的 后的 [number] 行 grep -A number pattern files # 反向查找 “不匹配” 的行 grep -v dis_pattern files # 正则表达式查找 1 grep -E "[1-9]+" # 正则表达式查找 2 egrep "[1-9]+" # 不显示错误信息 grep -s # 按匹配文件中内容查询 grep -f pattern_file file # 不区分大小写地搜索。默认情况区分大小写, grep -i pattern files # 只列出匹配的文件名, grep -l pattern files # 列出不匹配的文件名, grep -L pattern files # 只匹配整个单词,而不是字符串的一部分(如匹配‘magic’,而不是‘magical’), grep -w pattern files # 显示匹配 pattern1 或 pattern2 的行, grep pattern1 | pattern2 files # 显示既匹配 pattern1 又匹配 pattern2 的行。 grep pattern1 files | grep pattern2
grep -a “systemd” /var/log/daemon.log | grep “snmp” grep -a “systemd” | “snmp” /var/log/daemon.log
–group-directories-first
16.1. 倒序查看 n 行 符合条件行 1 sudo grep -E 'Psu|Fan|Sff|Linecard' /var/log/syslog | sort -r | head -n 40
17. 查看某容器中 打印到 某文件的进程列表 1 2 grep -a "bgp" /var/log/syslog | awk '{ print $7 }' | uniq | sort | uniq grep -a "bgp" /var/log/user.log | awk '{ print $7 }' | uniq | sort | uniq
18. 查看某进程打印日志的类别 列表 1 grep -a "database" /var/log/user.log | awk '{ print $4 }' | uniq | sort | uniq
19. shell 脚本中临时调用 pexpect 1 2 3 4 5 6 7 expect -c " spawn scp lih@10.32.19.100:/home/lih/pexpect-2.3.tar.gz $RUN_PATH expect \"assword:\" send \"$PASSWD\r\" expect eof "
20. tmux 常用命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 新建会话 tmux new -s user_session_name # 查看已创建的会话 tmux ls # 进入一个已创建的会话 tmux a -t user_session_name # 暂时跳出当前会话(快捷键) # 1. 先按 control + B 后松开(触发 tmux 功能键监听) # 2. 再按 D (跳出会话窗口) # Kill 远程会话 tmux kill-session -t user_session_name
21. tmux 快捷键 均为先按 ctrl + b,放开后再按:
分屏
光标切换: o
会话终端切换: s
退出终端窗口: d
终止终端窗口: &
在当前窗口基础上再开一个新窗口: c
关闭所有分屏后的窗口: !
终端内显示时间: t
显示终端编号:q