1. 程式人生 > >初試Shell指令碼快三原始碼修復

初試Shell指令碼快三原始碼修復

初試Shell指令碼 背景 臨上線前快三原始碼修復QQ2952777280【話仙原始碼論壇】hxforum.com 測試比較努力,遇到閃退或者其他問題,會把日誌包打給我,由於app記憶體限制,目前每次打包都是1m大小,所以有時查詢問題的上下文比較吃力。同時由於日誌比較多,根據關鍵詞過濾的需求越來越重要。 於是決定學寫指令碼完成這個任務,根據我的要求,工作流程應該是傳入壓縮包,根據字尾名解壓,根據日期排序後合併成一個檔案,按需過濾關鍵詞。 — ## 先上程式碼 ```shell #!/usr/bin/env bash # Created By Vanch at 2018/9/20 printHelp() { echo “Uncompess log files from inputed zip” echo “Then Merge these logs to one file” echo “Supported file types: zip tar tar.gz tar.bz2” echo echo “Use -s for filtering socket result to socket.log” echo echo “Have fun!” } #如果沒輸入引數,就列印幫助資訊 if [ # -eq 0 ]; then printHelp exit 0 fi

#把長選項轉到短選項 for arg in “# -eq 0 ]; then printHelp exit 0fi#把長選項轉到短選項for arg in “@”; do shift case “arg"in"−−help”)set−−"arg"in"−−help”)set−−"@" “-h” ;; “–version”) set – “@”“−v”;;“−−list”)set−−"@"“−v”;;“−−list”)set−−"@" “-l” ;; *) set – “@”"@"“arg” esac done #獲取短選項 OPTIND=1 printS=false; while getopts “dmksahvl” opt; do case opt in h) #輸入為help,就列印幫助資訊 printHelp exit 0;; l) #支援單獨獲取支援檔案字尾列表 echo “Supported file types: zip tar tar.gz tar.bz2” exit 0;; v) #支援查詢版本號 echo “1.0.0” exit 0;; s) #過濾Socket printS=true;; esac done

#獲得壓縮包地址 file=opt in h) #輸入為help,就列印幫助資訊 printHelp exit 0;; l) #支援單獨獲取支援檔案字尾列表 echo “Supported file types: zip tar tar.gz tar.bz2” exit 0;; v) #支援查詢版本號 echo “1.0.0” exit 0;; s) #過濾Socket printS=true;; esacdone#獲得壓縮包地址file={!#} #如果不存在就退出 if [ ! -f “file” ]; then echo “File not exist!” exit 0; fi #獲取壓縮字尾 fileName=basenamefile" ]; then echo "File not exist!" exit 0;fi #獲取壓縮字尾fileName=

basenamefilesuffix={fileName#*.} #判斷檔案型別 support=('tar','tar.gz','tar.bz2','zip') if [ -zecho “{fileName#.}#判斷檔案型別support=(‘tar’,‘tar.gz’,‘tar.bz2’,‘zip’)if [ -z echo "{support[@]}" | grep -w "suffix" ] ; then echo “File type not support!” exit 0; fi #拼接資料夾地址 fileDir=suffix"` ] ; then echo “File type not support!” exit 0; fi#拼接資料夾地址fileDir=(dirname file)/file)/{fileName%%.} if [ -d fileDir];thenrm−rffileDir];thenrm−rffileDir fi mkdir fileDircdfileDircdfileDir #解壓檔案 case suffixin′tar′)eval"tarxvfsuffixin′tar′)eval"tarxvffile > /dev/null 2>&1”;; ‘tar.gz’) eval “tar zxvf file > /dev/null 2>&1”;; ‘tar.bz2’) eval “tar jxvffile > /dev/null 2>&1”;; ‘tar.bz2’) eval “tar jxvffile > /dev/null 2>&1”;; ‘zip’) eval “unzip -o file > /dev/null 2>&1”;; esac echo ‘Uncompass Success!’

#獲取日誌列表,按排序合併到一個日誌 mergeFile=./merge.log logCount=0 #搜尋com開頭的日誌,按日期排序,用?臨時代替空格 for logName in ls | grep 'com' | sort -n | tr " " "?"; do logName=file > /dev/null 2>&1";;esacecho ‘Uncompass Success!’#獲取日誌列表,按排序合併到一個日誌mergeFile=./merge.loglogCount=0#搜尋com開頭的日誌,按日期排序,用?臨時代替空格for logName in ls | grep 'com' | sort -n | tr " " "?"; do logName={logName//’?’/’ '} cat ./“logName”>>logName">>mergeFile ((logCount++)) done #不存在日誌就打斷 if [ logCount -eq 0 ]; then echo “Log not exist!” exit fi echo ‘Merge Success!’ #列印socket if [logCount -eq 0 ]; then echo “Log not exist!” exit fiecho ‘Merge Success!’#列印socketif [printS = true ]; then cat mergeFile | grep -i ‘socket’ >> ./socket.log echo ‘Filter socket’ fi

---
## 遇到的問題
查詢了很多資料後寫完了這個指令碼,基本滿足了我的需求,下面總結一下怎麼解決遇到的問題。

### 使用環境
一開始學指令碼時,書上都說`#! /bin/bash`,但是看專案中大神寫的指令碼,都是`#!/usr/bin/env bash`,有什麼區別呢?

> 指令碼用env啟動的原因,是因為指令碼直譯器在linux中可能被安裝於不同的目錄,env可以在系統的PATH目錄中查詢。
> 同時,env還規定一些系統環境變數。

不同的系統,直譯器的路徑可能也不同,所以使用絕對路徑是比較危險的方式。通過從環境中查詢,可以保證相容性。

---

### 獲取選項
開發中我們經常用到命令,這些命令一般都配合選項達到不同的效果,比如最常用的`ls -al`,通過`-a`來指定結果包含隱藏檔案,通過`-l`達到列表顯示的效果。

通過查詢相關資料,我發現獲取選項普遍的做法是使用`getopts`命令,但是這個方法只能獲取`-h`這種短選項,對於`--help`長選項就不行。

第一種辦法是換成`getopt`命令,但是並不是每個系統都支援這個命令。具體使用和`getopts`類似,比如`getopt -o ab:c -l a-long:b-long`

第二種方法是把支援的長命令轉成短命令,我使用的就是這種方式,相對來說比較容易理解,且case寫的比較統一。通過`shift`取出引數,再`set --`的方式重寫,最後`OPTIND=1`把指標指回第一個選項。

---

### 檔案路徑和檔案字尾
按需求需要判斷後綴名來解壓,那麼就需要判斷`tar.gz`之類的問題。同時,如果傳入的檔案目錄是隱藏目錄,也會造成一定的障礙。我們假設傳入檔案路徑為`/a/.b/c.tar.gz`。

>mergeFile | grep -i 'socket' >> ./socket.log    echo 'Filter socket'fi```---## 遇到的問題查詢了很多資料後寫完了這個指令碼,基本滿足了我的需求,下面總結一下怎麼解決遇到的問題。### 使用環境一開始學指令碼時,書上都說`#! /bin/bash`,但是看專案中大神寫的指令碼,都是`#!/usr/bin/env bash`,有什麼區別呢?> 指令碼用env啟動的原因,是因為指令碼直譯器在linux中可能被安裝於不同的目錄,env可以在系統的PATH目錄中查詢。> 同時,env還規定一些系統環境變數。不同的系統,直譯器的路徑可能也不同,所以使用絕對路徑是比較危險的方式。通過從環境中查詢,可以保證相容性。---### 獲取選項開發中我們經常用到命令,這些命令一般都配合選項達到不同的效果,比如最常用的`ls -al`,通過`-a`來指定結果包含隱藏檔案,通過`-l`達到列表顯示的效果。通過查詢相關資料,我發現獲取選項普遍的做法是使用`getopts`命令,但是這個方法只能獲取`-h`這種短選項,對於`--help`長選項就不行。第一種辦法是換成`getopt`命令,但是並不是每個系統都支援這個命令。具體使用和`getopts`類似,比如`getopt -o ab:c -l a-long:b-long`第二種方法是把支援的長命令轉成短命令,我使用的就是這種方式,相對來說比較容易理解,且case寫的比較統一。通過`shift`取出引數,再`set --`的方式重寫,最後`OPTIND=1`把指標指回第一個選項。---### 檔案路徑和檔案字尾按需求需要判斷後綴名來解壓,那麼就需要判斷`tar.gz`之類的問題。同時,如果傳入的檔案目錄是隱藏目錄,也會造成一定的障礙。我們假設傳入檔案路徑為`/a/.b/c.tar.gz`。>{param#pattern}	從param前面刪除pattern的最小匹配 > > {param##pattern}	從param前面刪除pattern的最大匹配
>
>{param##pattern}	從param前面刪除pattern的最大匹配>>{param%pattern}	從param後面刪除pattern的最小匹配 > > {param%%pattern}	從param後面刪除pattern的最大匹配

如果按照`{param%%pattern}	從param後面刪除pattern的最大匹配如果按照`{fileName##*.}`來擷取,那麼只能拿到`gz`。 如果按照`{fileName#*.}`來擷取,拿到的又是`b/c.tar.gz`。那怎麼辦呢?

好在有`dirname`可以直接獲取檔案路徑,`basename`拿到檔名,單獨對檔名進行`{fileName#*.}`來擷取,拿到的又是`b/c.tar.gz`。那怎麼辦呢?好在有`dirname`可以直接獲取檔案路徑,`basename`拿到檔名,單獨對檔名進行`{fileName#*.}`就可以拿到`tar.gz`了。 --- ### 去除不必要的列印 執行解壓命令時,會列印解壓步驟,一般來說也需要顯示,那如果我們不想要打印出來呢?有一個辦法就是在命令之後加上`> /dev/null 2>&1` > /dev/null :代表空裝置檔案 > >\> :代表重定向到哪裡,例如:echo "123" > /home/123.txt > >1 :表示stdout標準輸出,系統預設值是1,所以">/dev/null"等同於"1>/dev/null" > >2 :表示stderr標準錯誤 > >& :表示等同於的意思,2>&1,表示2的輸出重定向等同於1 所以含義就是把命令輸出結果和錯誤輸出重定向,使得輸出不在當前螢幕顯示,由於null比較特殊,向這個檔案輸入等於進入黑洞,因此達到效果。 --- ### 陣列與空格 使用`ls | grep`的方式來過濾結果獲取檔名陣列的最大問題是,如果檔名包含空格,那麼前後會被分割成兩個單元,導致處理比較困難。 比較討巧的方法是臨時用特殊符號代替空格,在使用時再替換回來。這種方法不會改變檔名,也不用寫複雜的數組合並,比較符合簡單的設計。 ```shell tr " " "?" ${logName//'?'/' '} ```## 總結 通過這次簡單的指令碼實驗,對shell有了新的認識,及時記錄遇到的問題,相信下次會更有印象。使用指令碼,可以讓工作更有效率,相信以後也會越用越多。