初試Shell腳本

背景

臨上線前測試比較努力,遇到閃退或者其餘問題,會把日誌包打給我,因爲app內存限制,目前每次打包都是1m大小,因此有時查找問題的上下文比較吃力。同時因爲日誌比較多,根據關鍵詞過濾的需求愈來愈重要。linux

因而決定學寫腳本完成這個任務,根據個人要求,工做流程應該是傳入壓縮包,根據後綴名解壓,根據日期排序後合併成一個文件,按需過濾關鍵詞。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 "$@"; do
  shift
  case "$arg" in
    "--help")       set -- "$@" "-h" ;;
    "--version")    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=${!#}
#若是不存在就退出
if [ ! -f "$file" ]; then
    echo "File not exist!"
    exit 0;
fi 
#獲取壓縮後綴
fileName=`basename $file`
suffix=${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=$(dirname $file)/${fileName%%.*}
if [ -d $fileDir ]; then
    rm -rf $fileDir
fi
mkdir $fileDir
cd $fileDir
#解壓文件
case $suffix in
    'tar')
        eval "tar xvf $file > /dev/null 2>&1";;
    'tar.gz')
        eval "tar zxvf $file > /dev/null 2>&1";;
    'tar.bz2')
        eval "tar jxvf $file > /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=${logName//'?'/' '}
    cat ./"$logName" >> $mergeFile
    ((logCount++))
done
#不存在日誌就打斷
if [ $logCount -eq 0 ]; then
    echo "Log not exist!"
    exit 
fi
echo 'Merge Success!'
#打印socket
if [ $printS = true ]; then
    cat $mergeFile | grep -i 'socket' >> ./socket.log
    echo 'Filter socket'
fi
複製代碼

遇到的問題

查詢了不少資料後寫完了這個腳本,基本知足了個人需求,下面總結一下怎麼解決遇到的問題。數組

使用環境

一開始學腳本時,書上都說#! /bin/bash,可是看項目中大神寫的腳本,都是#!/usr/bin/env bash,有什麼區別呢?bash

腳本用env啓動的緣由,是由於腳本解釋器在linux中可能被安裝於不一樣的目錄,env能夠在系統的PATH目錄中查找。 同時,env還規定一些系統環境變量。app

不一樣的系統,解釋器的路徑可能也不一樣,因此使用絕對路徑是比較危險的方式。經過從環境中查找,能夠保證兼容性。socket


獲取選項

開發中咱們常常用到命令,這些命令通常都配合選項達到不一樣的效果,好比最經常使用的ls -al,經過-a來指定結果包含隱藏文件,經過-l達到列表顯示的效果。測試

經過查詢相關資料,我發現獲取選項廣泛的作法是使用getopts命令,可是這個方法只能獲取-h這種短選項,對於--help長選項就不行。ui

第一種辦法是換成getopt命令,可是並非每一個系統都支持這個命令。具體使用和getopts相似,好比getopt -o ab:c -l a-long:b-longspa

第二種方法是把支持的長命令轉成短命令,我使用的就是這種方式,相對來講比較容易理解,且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的最大匹配

若是按照${fileName##*.}來截取,那麼只能拿到gz。 若是按照${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的方式來過濾結果獲取文件名數組的最大問題是,若是文件名包含空格,那麼先後會被分割成兩個單元,致使處理比較困難。

比較討巧的方法是臨時用特殊符號代替空格,在使用時再替換回來。這種方法不會改變文件名,也不用寫複雜的數組合並,比較符合簡單的設計。

tr " " "?"
${logName//'?'/' '}
複製代碼

總結

經過此次簡單的腳本實驗,對shell有了新的認識,及時記錄遇到的問題,相信下次會更有印象。使用腳本,可讓工做更有效率,相信之後也會越用越多。

相關文章
相關標籤/搜索