Shell 小技能
这也是一种编程。
Shell 是一门短小精悍的胶水型语言,可以组合各种 Linux 实用工具进行日常临时任务处理。Shell 就像一把匕首,其强大之处,在于能够灵活组合能力。
掌握 Shell命令组合方式也是一个实用编程小技能。
Shell 组合
Shell 命令组合主要有如下方式:
- | : 管道符号,将上一个命令的结果写入一个临时文件,然后读取每一行作为输入传递到下一个命令的参数里。
- >, < : 重定向符号,将输出重定向到文件( 或标准输入输出)里,或者重定向指向文件输入(标准输入输出)。
- && : 组合执行多个命令。
- $(cmd) 将 cmd 的命令执行结果原地替换到其所在的位置。
- 正则表达式:通常用于 grep, sed, awk 程序中,筛选、替换满足条件的文本。
- cut:根据指定字段、指定列筛选指定的列或列集合。
- awk:根据指定字段或指定条件筛选列或列集合;生成格式化内容。
- grep : 根据指定正则表达式筛选满足正则表达式的行。
- sed: 根据指定正则表达式替换文本。
- find: 筛选满足条件的文件并输出文件路径。
- xargs: 批量处理命令,将上一个命令的执行结果的每一行通过管道传递给 xargs 指定的命令的参数。{} 作为参数占位符。
- sort: 根据指定列排序。
以下给出日常开发工作中的一些实际任务及例子,读者可以在自己的工作中多练习多体会,逐渐掌握。如果有不懂不会的,就问 AI 吧。
文本处理
文本处理常用工具:cat, grep, awk, sed, cut, sort, uniq
提取关键字并组成数组查询条件
排查问题或故障修复时,常常需要从日志里提取所需要的内容,并拼成数据库的 in 条件。
解读:
- cat : 读取和显示文件内容;
- awk: 筛选指定分隔符后面的字段内容;根据指定格式生成行内容;
- grep: 筛选含有指定关键字或匹配正则的行;
- sed: 文本替换。
- | : 管道符号,将上一个命令的结果作为输入传递到下一个命令的参数里。
cat webfileexist.txt | awk -F 'existDetectionId: ' '{print $2}' | grep -v "^$" | awk '{printf "%s%s", (NR>1?",":""), "\""$0"\""} END{print "]"}' | sed 's/^/[/'
webfileexist.txt
webfile is exist existDetectionId: abcdeft
webfile is exist existDetectionId: ggwsdf
输出
["abcdeft", "ggwsdf"]
筛选/排序匹配的列
可以打印日志耗时,然后从日志中提取耗时信息,生成数据和图表。
awk -F'=' ' $4 > 50 {print } ' rt_costs.txt > rt_50_costs.txt
awk -F'=' ' {print $3} ' rt_costs.txt | sed 's/, cost_time//g' | sort | uniq -c | awk '{print $2" "$1}' | sort -rnk2
rt_costs.txt
2023-04-26 16:29:16.392 [INFO]: [ids_detection_kafka-worker-24] - c.q.i.d.p.MethodMeasureAspect - detectionId=3f347c3e36d04feb939ac783931d5070252, method=DetectionDoSaver_process, cost_time=94
2023-04-26 16:29:16.392 [INFO]: [ids_detection_kafka-worker-27] - c.q.i.d.p.MethodMeasureAspect - detectionId=90661520f1fa47269d6ea930041e8a23255, method=DetectionDoSaver_process, cost_time=93
2023-04-26 16:29:16.397 [INFO]: [ids_detection_kafka-worker-26] - c.q.i.d.p.MethodMeasureAspect - detectionId=62163fa11af840a584286d322575ef7e254, method=DetectionFixedFilter_process, cost_time=2
日志查看和处理
tail -100f info.log | grep "method="
grep -E "A|B" info.log
ls info.20220616.* | xargs -I {} grep "cdcCheckCache hit is black" {} > /home/blackhit.log
ls info.20220615.* | xargs -I {} grep "send webshell cdc task to kafka, size" {} | cut -f 5 -d ":" | sed 's/^[ \t]*//g' | awk '{sum += $1};END {print sum}'
grep -r "cdcCheckCache hit is black" info.20220616.*
kubectl logs -f $(kubectl get po -A | grep ids-detect | awk '{print $2}') -n $(kubectl get po -A | grep ids-detect | awk '{print $1}') main | grep --color=auto "cost_time" | awk -F"=" ' $3 > 50 {print } '
文件处理
通常用 find 查找到满足指定条件的文件集合,然后用 xargs -I {} 命令 {} 来逐一处理。其中 {} 是将 find 命令查到的结果逐个取出的值。
找到满足指定条件的文件集合中的重复文件
find . -name "*.java" > /tmp/javafile.txt && sed -E 's?^\./.+/([a-zA-Z]+\.java).*$?\1?g' /tmp/javafile.txt | sort | uniq -d
复制或删除大量文件
避免 shell argument too long 报错。
find . -name "*.java" | xargs -I {} cp {} /tmp
find . -name "*.java" | xargs -I {} rm -rf {}
查找和删除文件
find ~/[0-9]* -name "*.csv" -mtime +29 -type f|while read file; do rm -f $file; done
find ~/ -size +100M -mtime +27 -type f | while read file; do rm -f $file; done
find . -size +100M | xargs -I {} ls -hl {}
查看目录占用空间情况
磁盘快满,需要看看磁盘空间占用情况,考虑可以清理哪些文件。
du -ahx | sort -rh | head -5
du -d 1 -h | sort -rh | head -20
du -ah /var/ | sort -rh | head -10
日常任务管理
查看占用80端口的进程
有时部署应用时,会报 80 端口已占用。此时,需要找到占用 80 端口的进程并杀死进程。注意:必须加 sudo 才会展示进程PID。
sudo kill -9 $(sudo netstat -lnp | grep :80)
批量杀死指定关键字的进程
ps aux | grep "$1" | awk '{print $2}' | xargs -I {} sudo kill -9 {}
supervisorctl
启动和重启命令。
这里主要展示如何筛选指定条件的结果中的字段、生成命令内容、写入文件和执行文件的方法。
grep 根据关键字筛选行; cut 根据分隔符和指定字段位置筛选列; awk 根据结果生成命令; > 将内容写入文件; && 用于连接多个命令。
sudo supervisorctl status | grep RUNNING | cut -f 1 -d' ' | grep '\-8' | awk '{print "sudo supervisorctl stop " $0"\n" }' > /tmp/stop.sh && sh /tmp/stop.sh
sudo supervisorctl status | grep STOPPED |cut -f 1 -d' ' | grep '\-8' | awk '{print "sudo supervisorctl start " $0"\n" }' > /tmp/restart.sh && sh /tmp/restart.sh
批量调用 API
用文件里的数据填充 curl 里的占位符,生成命令内容。
bcurl.sh
#!/bin/bash
file=$1
while read line
do
echo '\n\n'$line
curl -H "Content-Type: x-www-form-urlencoded" -X POST -d '{"c_version":"1.0", "c_appid":"xxx", "c_action": "TiInfo", "key": "'$line'", "type":"ipIngress"}' http://127.0.0.1:9900/api/v1/
done < $file
sh bcurl.sh ips.txt
AI 来帮忙
如果你不熟悉 Shell ,也没关系,让 AI 来帮忙。 你只负责出题即可。
出题:
我有一个命令文件,每一行都是一个命令,写一个 linux 命令组合,读取文件里的每一个命令并执行。必须是能够在 shell 上单行输入的。
cmd.txt
ls -1 ~/ | wc -l
ls -1 ~/workspace | wc -l
ls -1 ~/joy | wc -l
AI 就会给出回复。然后尝试执行下即可。
你还可以添加更多要求:希望能输出每一行及对应的命令结果;并发执行这些命令等。
小结
如果把一个个 Linux 实用命令看作是一个 API, 那么组合这些实用命令完成实际任务,跟日常软件开发已经很接近了。
如果不想总是从字符开始写程序,那么学习 linux 命令,创建实用工具,倒也不失为一种乐趣。