Shell 小技能

琴水玉發表於2024-05-26

這也是一種程式設計。

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

相關文章