理解 Bash 中的尖括號

2019-02-02 20:35:00

為初學者介紹尖括號。

Bash 內建了很多諸如 lscdmv 這樣的重要的命令,也有很多諸如 grepawksed 這些有用的工具。但除此之外,其實 Bash 中還有很多可以起到膠水作用的標點符號,例如點號(.)、逗號(,)、括號(<>)、引號(")之類。下面我們就來看一下可以用來進行資料轉換和轉移的尖括號(<>)。

轉移資料

如果你對其它程式語言有所了解,你會知道尖括號 <> 一般是作為邏輯運算子,用來比較兩個值之間的大小關係。如果你還編寫 HTML,尖括號作為各種標籤的一部分,就更不會讓你感到陌生了。

在 shell 指令碼語言中,尖括號可以將資料從一個地方轉移到另一個地方。例如可以這樣把資料存放到一個檔案當中:

ls > dir_content.txt

在上面的例子中,> 符號讓 shell 將 ls 命令的輸出結果寫入到 dir_content.txt 裡,而不是直接顯示在命令列中。需要注意的是,如果 dir_content.txt 這個檔案不存在,Bash 會為你建立;但是如果 dir_content.txt 是一個已有的非空檔案,它的內容就會被覆蓋掉。所以執行類似的操作之前務必謹慎。

你也可以不使用 > 而使用 >>,這樣就可以把新的資料追加到檔案的末端而不會覆蓋掉檔案中已有的資料了。例如:

ls $HOME > dir_content.txt; wc -l dir_content.txt >> dir_content.txt

在這串命令裡,首先將家目錄的內容寫入到 dir_content.txt 檔案中,然後使用 wc -l 計算出 dir_content.txt 檔案的行數(也就是家目錄中的檔案數)並追加到 dir_content.txt 的末尾。

在我的機器上執行上述命令之後,dir_content.txt 的內容會是以下這樣:

ApplicationsbincloudDesktopDocumentsDownloadsGamesISOsliblogsMusicOpenSCADPicturesPublicTemplatestest_dirVideos17 dir_content.txt

你可以將 >>> 作為箭頭來理解。當然,這個箭頭的指向也可以反過來。例如,Coen brothers (LCTT 譯註:科恩兄弟,一個美國電影導演組合)的一些演員以及他們出演電影的次數儲存在 CBActors 檔案中,就像這樣:

John Goodman 5John Turturro 3George Clooney 2Frances McDormand 6Steve Buscemi 5Jon Polito 4Tony Shalhoub 3James Gandolfini 1

你可以執行這樣的命令:

sort < CBActorsFrances McDormand 6 # 你會得到這樣的輸出George Clooney 2James Gandolfini 1John Goodman 5John Turturro 3Jon Polito 4Steve Buscemi 5Tony Shalhoub 3

就可以使用 sort 命令將這個列表按照字母順序輸出。但是,sort 命令本來就可以接受傳入一個檔案,因此在這裡使用 < 會略顯多餘,直接執行 sort CBActors 就可以得到期望的結果。

如果你想知道 Coens 最喜歡的演員是誰,你可以這樣操作。首先:

while read name surname films; do echo $films $name $surname > filmsfirst.txt; done < CBActors

上面這串命令寫在多行中可能會比較易讀:

while read name surname films;\ do echo $films $name $surname >> filmsfirst;\ done < CBActors

下面來分析一下這些命令做了什麼:

  • while …; do … done 是一個迴圈結構。當 while 後面的條件成立時,dodone 之間的部分會一直重複執行;
  • read 語句會按行讀入內容。read 會從標準輸入中持續讀入,直到沒有內容可讀入;
  • CBActors 檔案的內容會通過 < 從標準輸入中讀入,因此 while 迴圈會將 CBActors 檔案逐行完整讀入;
  • read 命令可以按照空格將每一行內容劃分為三個欄位,然後分別將這三個欄位賦值給 namesurnamefilms 三個變數,這樣就可以很方便地通過 echo $films $name $surname >> filmsfirst;\ 來重新排列幾個欄位的放置順序並存放到 filmfirst 檔案裡面了。

執行完以後,檢視 filmsfirst 檔案,內容會是這樣的:

5 John Goodman3 John Turturro2 George Clooney6 Frances McDormand5 Steve Buscemi4 Jon Polito3 Tony Shalhoub1 James Gandolfini

這時候再使用 sort 命令:

sort -r filmsfirst

就可以看到 Coens 最喜歡的演員是 Frances McDormand 了。(-r 參數列示降序排列,因此 McDormand 會排在最前面)