本文修改自《DevOps三十六计》中的Linux shell三十六计篇,原文作者阿铭,著有《跟阿铭学Linux》一书。
特殊命令
-
第一计
date可以格式化输出时间,定义文件名的前缀或者后缀。如:
[root@VM_0_9_centos logs]# ls
server.2018-07-02.log server.2018-07-12.log server.2018-08-01.log server.2018-08-02.log
[root@VM_0_9_centos logs]# date
Sat Aug 4 16:24:57 CST 2018
[root@VM_0_9_centos logs]# date -d '2 days ago' +%Y-%m-%d
2018-08-02
[root@VM_0_9_centos logs]# date +%Y-%m-%d
2018-08-04
[root@VM_0_9_centos logs]# rm *`date -d '2 days ago' +%Y-%m-%d`.log
rm: remove regular empty file ‘server.2018-08-02.log’? y
[root@VM_0_9_centos logs]# ls
server.2018-07-02.log server.2018-07-12.log server.2018-08-01.log
[root@VM_0_9_centos logs]#
#笔者经常用这个命令匹配日志文件,然后放到crontab定时任务中,定时删除一定时间前的无用日志。
#不过,习惯上的`date +"%Y%m%d_%H:%M"` 和 $(date +"%Y%m%d_%H:%M")在crontab下不起作用,需采用如下形式 `date +"\%Y\%m\%d_\%H:\%M"` 和 $(date +"\%Y\%m\%d_\%H:\%M")
-
第二计
read -p可以实现用户交互。
-
第三计
exec 1>/tmp/1.log 2>/tmp/error.log可以定义正确输出和错误输出。
-
第四计
mkpasswd可生成随机字符串。
-
第五计
test可用于判定某条件是否成立,作为逻辑判断条件。
-
第六计
sleep可定义休眠时间,用于循环脚本中。
-
第七计
true和while可实现死循环,例如”while true”,它等同于”whiel:”。
-
第八计
在循环体里面巧用break或continue,可控制循环体结束或者继续。
-
第九计
echo -e识别换行符”\n”,echo -n忽略换行符。
-
第十计
嵌入文档(Here Documents)将脚本中自定义文本内容作为指定命令的输入,典型用法:cat << EOF。
正则三剑客
-
第十一计
正则表达式中特殊符号含义要搞清楚。”.”表示任意字符,”*”表示它前面的字符有0个或多个,”+”表示它前面的字符有1个或多个,”?”表示它前面的字符有0个或1个,”.*”表示任意个任意字符。
-
第十二计
grep的选项”–color”,将匹配的关键字显示为红色,方便定位。
-
第十三计
grep的”-E”选项支持扩展正则(表达式中含有”+” “?” “{}” “()” “|”等符号)匹配,如,grep -E ‘aaa|bbb’ filename,将匹配包含aaa或bbb的行。
-
第十四计
grep的”-r”选项实现遍历目录下所有文件。
-
第十五计
sed的”-i”选项直接修改文件内容。
-
第十六计
sed的”-r”选项支持扩展正则匹配,类似grep的”-E”选项。
-
第十七计
sed可以调换一个字符串里不同字段的位置,例如调换第一个单词和最后一个单词的位置。
-
第十八计
awk的”-F”选项指定的分隔符可以是一个正则表达式,如awk -F ‘(:|#)’,分隔符可以是”:”或”#”。
-
第十九计
awk调用shell的变量,需要做一个特殊处理:a=1;awk -v b=$a’{print b}’。
-
第二十计
awk可以进行数学计算,并且可以结合循环实现计算某一段的综合,如,awk -F ‘:’ ‘{sum += $3} END {print sum}’ /etc/passwd。
shell特殊符号
-
第二十一计
特殊符号”||”用在两条命令中间,表示左边的命令执行不成功时才会执行其右边的命令。
-
第二十二计
特殊符号”$”通常用来表示一个变量,如,a=1;echo $a。在shell中自身也有诸多自带变量,比如,”$1”为第一个参数,”$2”为第二个参数,依次类推。”$#”表示参数个数。”$”符号的用法还有很多,比如检查一条命令是否执行成功,根据返回值”$?”的值来判定。在正则表达式中,”$”表示结尾。
-
第二十三计
特殊符号”&&”也是在两条命令中间使用,但它和”||”含义正好相反:当其左边命令执行成功时才会执行其右边的命令。
-
第二十四计
反引号”`”(反引号在键盘左上角的波浪号键上)会将命令结果赋值给变量,方便调用。如:
[root@VM_0_9_centos ~]# ls
abc.txt ac.txt anaconda-ks.cfg a.txt b.txt test
[root@VM_0_9_centos ~]# result=`ls *.txt`
[root@VM_0_9_centos ~]# echo $result
abc.txt ac.txt a.txt b.txt
[root@VM_0_9_centos ~]#
-
第二十五计
管道符号”|”会将其左边命令的输出内容作为右边命令的输入内容。
-
第二十六计
通配符号”*”和正则表达式中的”*”含义不同,在shell里面它表示通配,如ls *.txt会把所有.txt为后缀的文件全部列出来。
-
第二十七计
转义符号”\”会将特殊符号变为普通字符。如ls *.txt会把所有.txt文件列出来,但如果使用ls \*.txt则只会把*.txt列出来,这里的”*.txt”就是文件的名字。
-
第二十八计
注释符号”#”后面的字符不再被shell解释。为了让shell脚本更容易被人读懂,应该加一些说明文字,这些文字的行首要加上”#”。
-
第二十九计
特殊符号”?”在shell中代表任何一个字符。比如ls ?.txt只把1.txt、2.txt、a.txt等列出来,而不会列出12.txt、aaa.txt。如:
[root@VM_0_9_centos ~]# ls
abc.txt ac.txt anaconda-ks.cfg a.txt b.txt test
[root@VM_0_9_centos ~]# ls a?.txt
ac.txt
shell技巧
-
第三十计
test -n “$a”可以判断变量a是否不为空,test -z “$a”可以判断变量a是否为空,两者正好相对。如:
[root@VM_0_9_centos ~]# a=`test -n "$b"`
[root@VM_0_9_centos ~]# echo $?
1
#上一行返回false,说明test -n "$b"的结果是false,即变量b是空,因为我们之前没定义这个变量
[root@VM_0_9_centos ~]# b=123
[root@VM_0_9_centos ~]# a=`test -n "$b"`
[root@VM_0_9_centos ~]# echo $?
0
#由于定义了b=123,这次返回的就是true
-
第三十一计
可以把一条命令作为if的判断条件,在shell脚本里很多情况下需要先判断一条命令是否执行成功,判断依据是根据命令执行后$?返回值是否是0。
-
第三十二计
如果在脚本中要处理的文本内容比较多,可以先存储到一个临时文件里,这样比存储到变量里更加方便,有时甚至是必要的,比如要处理超大文件时,全放变量里就等于放在了内存里。
-
第三十三计
调试脚本用-x,可以看到每一步运行过程,从而精准定位问题点。
-
第三十四计
crontab最小时间单元为分钟,while死循环结合sleep可以实现秒级的计划任务。
-
第三十五计
虚拟终端screen非常实用,虽然不能在shell脚本里面用,但是在调试脚本或者运行常驻脚本时,使用虚拟终端是非常方便的。
-
第三十六计
expect脚本可以实现自动执行交互式的命令,例如远程登录一台Linux服务器,并执行若干条命令,执行完后再退出。结合shell的for循环,可以实现批量操作。
其实笔者还有一些经常使用的命令推荐:
- lsof
lsof -i:port命令可以查看端口是否被占用,如:
[root@VM_0_9_centos ~]# lsof -i:8081
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 26271 root 116u IPv4 87571136 0t0 TCP *:tproxy (LISTEN)
[root@VM_0_9_centos ~]# lsof -i:8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 27382 root 49u IPv4 281971 0t0 TCP *:webcache (LISTEN)
[root@VM_0_9_centos ~]# lsof -i:8082
[root@VM_0_9_centos ~]#
#可见,8080和8081都被占用了,8082没有被占用