這也是一種程式設計。
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 命令,建立實用工具,倒也不失為一種樂趣。