本文修改自《DevOps三十六計》中的Linux shell三十六計篇,原文作者阿銘,著有《跟阿銘學Linux》一書。
特殊命令
-
第一計
date可以格式化輸出時間,定義文件名的前綴或者後綴。如:
[root@VM_0_9_centos logs]# ls
server.2018-07-02.log server.2018-07-12.log server.2018-08-01.log server.2018-08-02.log
[root@VM_0_9_centos logs]# date
Sat Aug 4 16:24:57 CST 2018
[root@VM_0_9_centos logs]# date -d '2 days ago' +%Y-%m-%d
2018-08-02
[root@VM_0_9_centos logs]# date +%Y-%m-%d
2018-08-04
[root@VM_0_9_centos logs]# rm *`date -d '2 days ago' +%Y-%m-%d`.log
rm: remove regular empty file ‘server.2018-08-02.log’? y
[root@VM_0_9_centos logs]# ls
server.2018-07-02.log server.2018-07-12.log server.2018-08-01.log
[root@VM_0_9_centos logs]#
#筆者經常用這個命令匹配日誌文件,然後放到crontab定時任務中,定時刪除一定時間前的無用日誌。
#不過,習慣上的`date +"%Y%m%d_%H:%M"` 和 $(date +"%Y%m%d_%H:%M")在crontab下不起作用,需採用如下形式 `date +"\%Y\%m\%d_\%H:\%M"` 和 $(date +"\%Y\%m\%d_\%H:\%M")
-
第二計
read -p可以實現用戶交互。
-
第三計
exec 1>/tmp/1.log 2>/tmp/error.log可以定義正確輸出和錯誤輸出。
-
第四計
mkpasswd可生成隨機字符串。
-
第五計
test可用於判定某條件是否成立,作爲邏輯判斷條件。
-
第六計
sleep可定義休眠時間,用於循環腳本中。
-
第七計
true和while可實現死循環,例如”while true”,它等同於”whiel:”。
-
第八計
在循環體裏面巧用break或continue,可控制循環體結束或者繼續。
-
第九計
echo -e識別換行符”\n”,echo -n忽略換行符。
-
第十計
嵌入文檔(Here Documents)將腳本中自定義文本內容作爲指定命令的輸入,典型用法:cat << EOF。
正則三劍客
-
第十一計
正則表達式中特殊符號含義要搞清楚。”.”表示任意字符,”*”表示它前面的字符有0個或多個,”+”表示它前面的字符有1個或多個,”?”表示它前面的字符有0個或1個,”.*”表示任意個任意字符。
-
第十二計
grep的選項”–color”,將匹配的關鍵字顯示爲紅色,方便定位。
-
第十三計
grep的”-E”選項支持擴展正則(表達式中含有”+” “?” “{}” “()” “|”等符號)匹配,如,grep -E ‘aaa|bbb’ filename,將匹配包含aaa或bbb的行。
-
第十四計
grep的”-r”選項實現遍歷目錄下所有文件。
-
第十五計
sed的”-i”選項直接修改文件內容。
-
第十六計
sed的”-r”選項支持擴展正則匹配,類似grep的”-E”選項。
-
第十七計
sed可以調換一個字符串裏不同字段的位置,例如調換第一個單詞和最後一個單詞的位置。
-
第十八計
awk的”-F”選項指定的分隔符可以是一個正則表達式,如awk -F ‘(:|#)’,分隔符可以是”:”或”#”。
-
第十九計
awk調用shell的變量,需要做一個特殊處理:a=1;awk -v b=$a’{print b}’。
-
第二十計
awk可以進行數學計算,並且可以結合循環實現計算某一段的綜合,如,awk -F ‘:’ ‘{sum += $3} END {print sum}’ /etc/passwd。
shell特殊符號
-
第二十一計
特殊符號”||”用在兩條命令中間,表示左邊的命令執行不成功時纔會執行其右邊的命令。
-
第二十二計
特殊符號”$”通常用來表示一個變量,如,a=1;echo $a。在shell中自身也有諸多自帶變量,比如,”$1”爲第一個參數,”$2”爲第二個參數,依次類推。”$#”表示參數個數。”$”符號的用法還有很多,比如檢查一條命令是否執行成功,根據返回值”$?”的值來判定。在正則表達式中,”$”表示結尾。
-
第二十三計
特殊符號”&&”也是在兩條命令中間使用,但它和”||”含義正好相反:當其左邊命令執行成功時纔會執行其右邊的命令。
-
第二十四計
反引號”`”(反引號在鍵盤左上角的波浪號鍵上)會將命令結果賦值給變量,方便調用。如:
[root@VM_0_9_centos ~]# ls
abc.txt ac.txt anaconda-ks.cfg a.txt b.txt test
[root@VM_0_9_centos ~]# result=`ls *.txt`
[root@VM_0_9_centos ~]# echo $result
abc.txt ac.txt a.txt b.txt
[root@VM_0_9_centos ~]#
-
第二十五計
管道符號”|”會將其左邊命令的輸出內容作爲右邊命令的輸入內容。
-
第二十六計
通配符號”*”和正則表達式中的”*”含義不同,在shell裏面它表示通配,如ls *.txt會把所有.txt爲後綴的文件全部列出來。
-
第二十七計
轉義符號”\”會將特殊符號變爲普通字符。如ls *.txt會把所有.txt文件列出來,但如果使用ls \*.txt則只會把*.txt列出來,這裏的”*.txt”就是文件的名字。
-
第二十八計
註釋符號”#”後面的字符不再被shell解釋。爲了讓shell腳本更容易被人讀懂,應該加一些說明文字,這些文字的行首要加上”#”。
-
第二十九計
特殊符號”?”在shell中代表任何一個字符。比如ls ?.txt只把1.txt、2.txt、a.txt等列出來,而不會列出12.txt、aaa.txt。如:
[root@VM_0_9_centos ~]# ls
abc.txt ac.txt anaconda-ks.cfg a.txt b.txt test
[root@VM_0_9_centos ~]# ls a?.txt
ac.txt
shell技巧
-
第三十計
test -n “$a”可以判斷變量a是否不爲空,test -z “$a”可以判斷變量a是否爲空,兩者正好相對。如:
[root@VM_0_9_centos ~]# a=`test -n "$b"`
[root@VM_0_9_centos ~]# echo $?
1
#上一行返回false,說明test -n "$b"的結果是false,即變量b是空,因爲我們之前沒定義這個變量
[root@VM_0_9_centos ~]# b=123
[root@VM_0_9_centos ~]# a=`test -n "$b"`
[root@VM_0_9_centos ~]# echo $?
0
#由於定義了b=123,這次返回的就是true
-
第三十一計
可以把一條命令作爲if的判斷條件,在shell腳本里很多情況下需要先判斷一條命令是否執行成功,判斷依據是根據命令執行後$?返回值是否是0。
-
第三十二計
如果在腳本中要處理的文本內容比較多,可以先存儲到一個臨時文件裏,這樣比存儲到變量裏更加方便,有時甚至是必要的,比如要處理超大文件時,全放變量裏就等於放在了內存裏。
-
第三十三計
調試腳本用-x,可以看到每一步運行過程,從而精準定位問題點。
-
第三十四計
crontab最小時間單元爲分鐘,while死循環結合sleep可以實現秒級的計劃任務。
-
第三十五計
虛擬終端screen非常實用,雖然不能在shell腳本里面用,但是在調試腳本或者運行常駐腳本時,使用虛擬終端是非常方便的。
-
第三十六計
expect腳本可以實現自動執行交互式的命令,例如遠程登錄一臺Linux服務器,並執行若干條命令,執行完後再退出。結合shell的for循環,可以實現批量操作。
其實筆者還有一些經常使用的命令推薦:
- lsof
lsof -i:port命令可以查看端口是否被佔用,如:
[root@VM_0_9_centos ~]# lsof -i:8081
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 26271 root 116u IPv4 87571136 0t0 TCP *:tproxy (LISTEN)
[root@VM_0_9_centos ~]# lsof -i:8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 27382 root 49u IPv4 281971 0t0 TCP *:webcache (LISTEN)
[root@VM_0_9_centos ~]# lsof -i:8082
[root@VM_0_9_centos ~]#
#可見,8080和8081都被佔用了,8082沒有被佔用