編程小技巧之 Linux 文本處理命令

合格的程序員都善於使用工具,正所謂君子性非異也,善假於物也。合理的利用 Linux 的命令行工具,能夠提升咱們的工做效率。java

本文簡單的介紹三個能使用 Linux 文本處理命令的場景,給你們開闊一下思路。但願你們閱讀完這篇文章以後,要多加實踐,將這些技巧內化到本身的平常工做習慣中,真正的提升效率。內化很重要,就像開玩笑所說的同樣,即便我知道高內聚,低耦合的要求,瞭解 23 種設計模式和 6 大原則,熟讀代碼整潔之道,卻仍然寫不出優秀的代碼。知道和內化到行爲中區別仍是很大的。nginx

能不能讓正確的原則指導正確的行動自己,其實就是區分是不是高手的一個顯著標志。程序員

程序員平常工做中每每要處理一些數據和文本,好比說統計一些服務日誌文件信息,根據數據庫數據生成一些處理數據的SQL和搜索文件內容等。能夠直接經過編寫代碼處理,但不夠便捷,由於有時候線上相關的代碼環境依賴不必定具有。而直接使用 Linux 的文本處理命令能夠很方便地處理這些問題。spring

日誌文件撈數據

在工做中,咱們每每須要對一些具備固定格式的文件進行信息統計,好比說根據 nginx 的 access.log 文件數據,計算出每一個後端 API 接口的調用次數,而且排序。sql

nginx 的 access.log 文件文件格式配置以下所示,每一個字段之間經過空格分隔開來。數據庫

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';
複製代碼

上述配置中字段含義以下:後端

  • $remote_addr : 發送請求的源地址
  • $remote_user : 發送請求的用戶信息
  • $time_local : 接收請求的本地時間
  • $request : 請求信息,好比說 http 的 method 和 路徑。
  • $status : 請求狀態,好比說 200、401或者 500。
  • $body_bytes_sent : 請求 body 字節數。
  • $http_referer : 域名。
  • $http_user_agent : 用戶端 agent 信息,通常就是瀏覽器信息
  • $http_x_forwarded_for : 其餘信息。

具體的一段 access.log 內容以下所示。設計模式

58.213.85.34 - - [11/Sep/2019:03:36:11 +0800] "POST /publish/pending/list HTTP/2.0" 200 1328 "https://remcarpediem.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"
58.213.85.34 - - [11/Sep/2019:03:36:30 +0800] "GET /publish/search_inner?key=test HTTP/2.0" 200 34466 "https://remcarpediem.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"
複製代碼

那麼,咱們能夠經過下面命令來統計全部接口調用的次數,而且從大到小排序顯示。瀏覽器

cat /var/log/nginx/access.log | awk '{print $7}' | awk -F'?' '{print $1}' | sort | uniq -c | sort -nr
複製代碼

這條命令涉及了 cat、awk、sort , uniq 四個命令行工具和 | 鏈接符的含義,咱們依次簡單講解一下它們的使用,感興趣的同窗能夠自行去全面瞭解學習。bash

cat 命令是將文件內容打印到標準輸出設備上,能夠是終端,也能夠是其餘文件。好比說:

cat /var/log/nginx/access.log # 打印到終端
cat /var/log/nginx/access.log > copy.log # 打印到其餘文件中
複製代碼

| 符號是管道操做符,它將的一個命令的 stdout 指向第二個命令的 stdin。在這條命令中 | 符號將 cat 命令的輸出指向到 awk 命令的輸入中。

awk 是貝爾實驗室 1977 年搞出來的文本流處理工具,用於對具備固定格式的文件進行流處理。好比說 nginx 的 access.log 文件,它各個字段之間經過空格分隔開來,awk 就很適合處理此類文件。

'{print $7}' 就是 awk 的指令聲明,表示打印出變量$7$7則是 awk 內置的變量,表明按照分隔符分隔開來的第七個文本內容。對於 access.log 文件來講就是 $request 表明的路徑相關的內容。 $request 的所有內容是POST /publish/pending/list HTTP/2.0$6 對應 POST,而 $7 對應的就是 /publish/pending/list

awk '{print $7}' Access.log # ''中是命令聲明,後邊跟着要操做的文件,也就是awk的輸入流。
複製代碼

可是有些時候咱們發現文本內容並非按照空格進行分隔的,好比說 $request 內容可能爲 /publish/search_inner?key=test,雖然是相同的 path,可是 query 不一樣,咱們統計接口調用量時須要將 query 部分過濾掉。咱們可使用 awk 的 -F 指令指定分隔符。

awk -F'?' '{print $1}' 
# 能夠將 /publish/search_inner?key=test 處理爲 /publish/search_inner
複製代碼

sort 是專門用於排序的命令,它有多個參數:

  • -n 按數值進行排序,默認是按照字符值排序,按照數值比較 10 > 2 可是按照字符值排序,2 >10 ,由於字符值會先比較首位,也就是 2 > 1。
  • -r 默認是升序排列,這個參數指定按照逆序排列。
  • -k N 指定按第N列排序,默認是第一個值
sort -nr Access.log # 按照數值逆序排序
複製代碼

最後一個命令是 uniq,它用於消除重複行,或者統計。

sort unsort.txt | uniq # 消除重複行
sort unsort.txt | uniq -c # 統計各行在文件中出現的次數,輸入格式是[字數] [內容]
sort unsort.txt | uniq -d # 找出重複行
複製代碼

好比說cat /var/log/nginx/access.log | awk '{print $7}' | awk -F'?' '{print $1}' | sort | uniq -c 命令的輸出以下所示,正好做爲 sort -nr 的輸入。

5 /announcement/pending/list
5 /announcement/search_inner
複製代碼

利用這些指令,咱們能夠經過 access.log 統計不少信息,好比下列這些信息( access.log 的信息配置不一樣,不能夠直接照搬 )。

cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’ 
#查找當前日誌文件 500 錯誤的訪問:
tail -f access.log | awk -F ‘^A’ ‘{if($6>1) print $0}’ 
#查找耗時超過 1s 的慢請求
複製代碼

數據庫SQL

在業務迭代過程當中,有些數據庫數據可能須要使用腳本去修改,這是咱們能夠要根據一些數據生成對應的 SQL 命令,這裏咱們可使用命令行工具快速生成。 好比說咱們要將一系列訂單狀態有問題,須要將其恢復成正常的狀態。你如今已經收集到了這批訂單的信息。

oder_id name info good_id
100000  '褲子' '山東' 1000
100001  '上衣' '江蘇' 1000
100002  '內衣' '內蒙古' 1000
........
100003  '襪子' '江西' 1000
複製代碼

那麼你可使用以下命令直接生成對應的 SQL 語句。

cat ErrorOrderIdFile | awk '{print"UPDATE ORDER SET state = 0 WHERE resource_id = "$1}'
複製代碼

這裏 ''中都是 awk 的命令內容,而""中是打印的純文本,因此咱們能夠將須要補充的 SQL 命令打印出來。

代碼信息統計

在大公司中,各個團隊每每會公開出本身的接口給兄弟團隊調用,可是隨着版本地快速迭代,公開的接口愈來愈多,想要關閉掉又每每不清楚上游調用方是哪一個部門的,輕易不敢關閉或者修改。這時,若是你能訪問整個公司的代碼庫,就能夠經過下面的腳本搜索一下項目中是否出現該接口相關的關鍵詞。

筆者公司團隊中微服務間經過 FeignClient 相互調用,因此對於這種狀況,能夠直接將搜索出對應 FeignClient 的函數名出現的文件名稱。

下面是一段在多個項目中統計某些關鍵詞出現次數,並打印出文件名的 bash 腳本。

#!/bin/bash
keyword=$1 # 將bash命令的第一個參數賦值給 keyword
prefix=`echo $keyword | tr -s '.' '|' | sed 's/$/|/'` # 處理前綴
files=`find services -name "*.java" -or -name "*.js" | xargs grep -il $keyword` 
# 最關鍵的一條,搜索services文件夾下文件名後綴爲.java或者.js而且內容中有關鍵詞的文件名稱。
if [ -z "$files" ];then
	echo ${prefix}0
fi
# 打印
for f in $files;do
echo "$prefix$f"
done
複製代碼

咱們只看一下最關鍵的 find 命令,其餘的命令好比 tr 或者 sed,你們能夠自行了解學習。

find 用於查找文件,能夠按照文件名稱、文件操做權限、文件屬主、文件訪問時間等條件來查找。

find services -name "*.java" -or -name "*.js" # 搜索 services 文件夾下
find . -atime 7 -type f -print 
# -atime是訪問時間,-type 是文件類型,區分文件和目錄,查找最近7天訪問過的文件。
find . -type f -user remcarpediem -print// 找用戶 remcarpediem 所擁有的文件
find . ! -name "*.java" -print # !是否認參數,查找全部不是以 .java 結尾的文件。
find . -type f -name "*.java" -delete # find 以後的操做,能夠刪除當前目錄下全部的 java 文件
find . type f -name "*.java" | xargs rm # 上邊語句的另一種寫法
複製代碼

xargs 命令可以將輸入數據轉化爲特定命令的命令行參數,好比說多行變一行等,串聯多個命令行,好比說上邊 find 和 rm。

> ls 
Sentinel					groovy-engine					spring-cloud-bus-stream-binder-rocketmq
agent-demo					hash						spring-cloud-stream-binder-rabbit
> ls | xargs # 將 ls 的輸出內容變成一行。
Sentinel agent-demo groovy-engine  hash spring-cloud-bus-stream-binder-rocketmq spring-cloud-stream-binder-rabbit
> echo "nameXnameXnameXname" | xargs -dX 
name name name name
# -d 選項能夠自定義一個定界符,相信你已經瞭解 xargs 的大體做用了吧,按照分隔符拆分文本到一行,默認分隔符當時是回車了。
複製代碼

最後一個命令時 grep,它是文本搜索命令,它能夠搜索文本內容的關鍵詞。

grep remcarpediem file # 將 file 文件中的帶有 remcarpediem 關鍵詞的行。
grep -C10 remcarpediem file # 將 file 文件中的帶有 remcarpediem 關鍵詞先後10行的內容。
cat LOG.* | grep "FROM " | grep "WHERE" > b # 將日誌中的全部帶where條件的sql查找查找出來
grep -li remcarpediem file # 忽略大小寫,而且打印出文件名稱
複製代碼

如今你們在回頭看一下這段 bash 腳本,是否是大體瞭解它執行的過程和原理啦。

files=`find services -name "*.java" -or -name "*.js" | xargs grep -il $keyword` 
複製代碼

後記

本文簡單介紹了程序員平常工做中可能用到 Linux 命令的三個場景。你們能夠根據本身的實際狀況,來判斷是否須要繼續全面詳細地學習相關的知識。畢竟只有能運用於實踐,給本身工做產生價值的技術纔是真技術。學習一項技術,就要堅持學以至用的目的。

我的博客地址,歡迎查看

相關文章
相關標籤/搜索