簡潔的bash程式設計技巧

糰子的部落格發表於2012-11-06

來源:糰子的部落格- ①

下面這幾條是我自己在寫shell程式碼的時候,比較喜歡的幾種寫法,拋磚引玉。

1) 檢查命令執行是否成功

第一種寫法,比較常見:

簡潔的寫法:

當然你也可以不要if/else,不過這樣可讀性比較差:

簡潔的Bash程式設計技巧

2) 將標準輸出與標準錯誤輸出重定向到/dev/null 第一種寫法,比較常見:

常見的錯誤寫法:

簡潔的寫法:

3) awk的使用

舉一個實際的例子,獲取Xen DomU的id。

常見的寫法:

簡潔的寫法:

4) 將一個文字的所有行用逗號連線起來

假設檔案內容如下所示:

使用Sed命令:

簡潔的寫法:

5) 過濾重複行

假設檔案內容如下所示:

常用的方法:

簡單的寫法:

6) grep查詢單詞

假設一個文字的每一行是一個ip地址,例如

使用grep查詢是否包括10.0.0.1這個ip地址。常見的寫法:

簡單的方法(其實這方法不見得簡單,只是為了說明-w這個引數還是很有用的)

順便grep的-n/-H/-v/-f/-c這幾引數都很有用。

7) 臨時設定環境變數

常見的寫法:

簡潔的寫法:

在命令之前加上環境變更的設定,只是臨時改變當前執行命令的環境。

8) $1,$2…等位置引數的使用

假設只想使用$2,$3..這幾個引數,常見的做法是:

為什麼不這樣寫呢?

9)退而求其次的寫法

相信大家會有這種需求,當一個引數值沒有提供時,可以使用預設值。常見的寫法是:

簡潔的寫法是這樣的:

10)bash特殊引數–的用法

假設要用grep查詢字串中是否包含-i,我們會這樣嘗試:

簡潔的方法是:

bash中–後面的引數不會被當作選項解析。

11)函式的返回值預設是最後一行語句的返回值

不要畫蛇添足再在後面加一行return $?了。

12) 將printf格式化的結果賦值給變數

例如將數字轉換成其十六進位制形式,常見的寫法是:

簡單的寫法是:

看看printf的help

13)列印檔案行

列印檔案的第一行:

列印檔案的第2行:

列印檔案的第2到5行:

列印檔案的第2行始(包括第2行在內)5行的內容:

列印倒數第二行:

14)善用let或者(())命令做算術運算

如何對一個數字做++運算,可能你會這樣用:

為何不用你熟悉的:

15)獲取軟連線指定的真實檔名

如果你不知道,你可能會這樣獲取:

如果你知道有一個叫readlink的命令,那麼:

16)獲取一個字元的ASCII碼

17)清空一個檔案

常見的用法:

簡單的寫法:

18) 不要忘記有here document

下面一段程式碼:

執行後有什麼問題嗎?

發現a這個變數沒有被賦值,為什麼呢?因為管道後面的程式碼是在在一個子shell中執行的,所做的任何更改都不會對當前shell有影響,自然a這個變數就不會有賦值了。

換一種思路,可以這樣做:

不過多了一個臨時檔案,最後還要刪除。這裡其實可以用到here document:

here document往往用於需要輸出一大段文字的地方,例如指令碼的help函式。

19)刪除字串中的第一個或者最後一個字元

假設字串為:

可能你第一個想法是通過sed或者其它命令來完成這個功能,但是其實有很簡單的方法:

類似地,你也可以刪除2個、3個、4個……

有沒有一次性刪除第一個和最後一個字元的方法呢?答案當然是肯定的:

關於這些變數替換的內容在bash的man手冊中都有說明。

20)使用逗號join陣列元素

假設陣列元素沒有空格,可以用這種方法:

假設陣列元素包含有空格,可以借用printf命令來達到:

21) Shell中的多程式

在命令列下,我們會在命令列後面加上&符號來讓該命令在後臺執行,在shell指令碼中,使用”(cmd)”可以讓fork一個子shell來執行該命令。利用這兩點,可以實現shell的多執行緒:

注意最後的wait命令,作用是等待所有子程式結束。

22) bash中alias的使用

alias其實是給常用的命令定一個別名,比如很多人會定義一下的一個別名:

以後就可以使用ll,實際展開後執行的是ls -l。

現在很多發行版都會帶幾個預設的別名,比如:

alias在某些方面確實提高了很大的效率,但是也是有隱患的,這點可以看我以前的一篇文章終端下肉眼看不見的東西。那麼如何不要展開alias,而是用本來的意思呢?答案是使用轉義:

在命令前面加一個反斜槓後就可以了。

這裡要插一段故事,前兩天我在shell指令碼中定義了下面的一個alias,假設位於檔案util.sh:

後面這串ssh選項是為了去掉一些warning的資訊,不提示輸入密碼等等。具體可以看ssh的文件說明。我自己測試的時候好好的,當時我同事跑得時候卻依然有報Warning。我對比了下我們兩個人的用法:

大家應該知道,直接./util.sh執行,shell會去找指令碼第一行的shebang中給定的直譯器去執行改指令碼,所以第二種用法相當於直接用bash來執行。那想必是bash/sh對alias是否預設展開這一點上是有區別的了(可能是bash版本的問題,RHEL 5U4)。翻閱了下Bash的man手冊,發現可以通過設定expand_aliases選項來開啟alias展開的功能,預設在非互動式Shell下是關閉的(什麼是互動式登入Shell)。

修改下util.sh,開啟這個選項就Ok了:

23)awk列印除第一列之外的其他列

awk用來擷取輸入行中的某幾列很有用,當時如果要排除某幾列呢?

例如有如下的一個檔案:

可以用下面的程式碼解決(來源):

但是前面多了一個空格,可以用cut命令稍微調整下:

 

附幾則小技巧:

1)sudo iptables -L -n | vim –

2)grep -v xxx | vim –

3)echo $’\”

4)set — 1 2 3; echo “$@”

5)搜尋stackoverflow/superuser等站點

相關文章