Bash 中使用控制運算子連線命令

2018-12-13 23:48:00

在命令列中,使用控制運算子為複合命令新增邏輯。

經常會使用一些簡單的複合指令,比如說在一個命令列中連線幾個命令。這些命令使用分號分隔,表示一個命令結束。為了在一個命令列中建立一系列簡單的 shell 命令,只需要使用分號把每一條命令分隔開,就像下面這樣:

command1 ; command2 ; command3 ; command4 ;

最後一個分號你可以不用新增,因為當你按下確認鍵時就表示一個命令的結束,但是為了和其它的保持一致,還是建議加上比較好。

所有的命令執行都沒有什麼問題 —— 只要沒有什麼意外發生。但是當出問題時到底發生了什麼呢?我們可以預測,並且通過 Bash 中內建的 &&|| 運算子跟蹤這些錯誤。這兩個控制運算子提供了一些流控制,可以讓我們改變程式碼執行佇列的順序。分號和換行符也被認為是 Bash 的控制運算子。

&& 運算子意義簡單來說就是“如果 command1 執行成功,就接著執行 command2。”如果 command1 因為任何原因執行失敗,那麼 command2 將不執行。這個語法看下來像這樣:

command1 && command2

這樣寫是允許的,因為每一個命令都會返回一個值(RC)給 shell 來表示這個命令在執行的過程中是否執行成功或者失敗。通常,返回值是 0 表示成功,而一個正數值表示不同種類的錯誤。有一些系統管理工具僅僅返回一個 1 來表示所有的錯誤,但是也有很多工具使用其它的正數的返回值來表示各種型別錯誤。

我們可以很容易的使用指令碼來檢查 shell 變數 $?,可以通過命令列表中的下一個命令,或者可以直接使用系統管理工具檢查。我們一起來看這些返回值。執行一個簡單的命令然後立即檢查它的返回值,這個返回值始終是屬於最後一個執行的命令。

[student@studentvm1 ~]$ ll ; echo "RC = $?"total 284-rw-rw-r--  1 student student   130 Sep 15 16:21 ascii-program.shdrwxrwxr-x  2 student student  4096 Nov 10 11:09 bin<snip>drwxr-xr-x. 2 student student  4096 Aug 18 10:21 VideosRC = 0[student@studentvm1 ~]$

這個返回值是 0,表示這個命令執行成功了。現在嘗試使用同樣的命令在一些我們沒有許可權的目錄上。

[student@studentvm1 ~]$ ll /root ; echo "RC = $?"ls: cannot open directory '/root': Permission deniedRC = 2[student@studentvm1 ~]$

這個返回值的含義可以在 ls 命令的 man 頁面 中找到。

現在我們來試試 && 這個控制運算子,因為它也可能會被用在一個命令列程式中。我們將從一個簡單的範例開始:建立一個新目錄,如果建立成功就在這個目錄中建立一個檔案。

我們需要一個目錄可以建立其它的目錄。首先,在你的家目錄中建立一個臨時的目錄用來做測試。

[student@studentvm1 ~]$ cd ; mkdir testdir

~/testdir 中新建一個目錄,這也應該是一個空目錄,因為是你剛剛建立的,然後建立一個新的空檔案在這個新目錄中。下面的命令可以做這些事情。

[student@studentvm1 ~]$ mkdir ~/testdir/testdir2 && touch ~/testdir/testdir2/testfile1[student@studentvm1 ~]$ ll ~/testdir/testdir2/total 0-rw-rw-r-- 1 student student 0 Nov 12 14:13 testfile1[student@studentvm1 ~]$

我們看到一切都執行得很好,因為 testdir 目錄是存取且可寫的。然後我們改變 testdir 目錄的許可權,讓使用者 student 不再具有存取的許可權。操作如下:

[student@studentvm1 ~]$ chmod 076 testdir ; ll | grep testdird---rwxrw-. 3 student student  4096 Nov 12 14:13 testdir[student@studentvm1 ~]$

在長列表(ll)命令後面使用 grep 命令來列出 testdir 目錄。你可以看到使用者 student 不再有 testdir 目錄的存取許可權。現在我們像之前一樣執行同樣的命令,但是在 testdir 目錄中建立的是一個不同的目錄。

[student@studentvm1 ~]$ mkdir ~/testdir/testdir3 && touch ~/testdir/testdir3/testfile1mkdir: cannot create directory ‘/home/student/testdir/testdir3’: Permission denied[student@studentvm1 ~]$

儘管我們也同樣得到了一個錯誤的訊息,但 && 控制運算子阻止了 touch 命令的執行,因為在建立 testdir3 目錄的時候發生了錯誤。通過這種複合的流控制可以阻止一些錯誤的發生使事情變亂。但是這樣看起來變得稍微複雜了一些。

|| 控制運算子允許新增另一個命令,這個命令在初始程式語句返回值大於 0 時執行。

[student@studentvm1 ~]$ mkdir ~/testdir/testdir3 && touch ~/testdir/testdir3/testfile1 || echo "An error occurred while creating the directory."mkdir: cannot create directory ‘/home/student/testdir/testdir3’: Permission deniedAn error occurred while creating the directory.[student@studentvm1 ~]$

當我們使用 &&|| 控制運算子時,使用流控制的複合命令的語法格式通常是下面這樣的形式。

preceding commands ; command1 && command2 || command3 ; following commands

使用控制運算子的複合命令可以在其它命令之前或者之後,這些和控制運算子流控制有關係,但是不受控制運算子流控制的影響。如果不考慮複合命令的流控制中發生的任何事情那麼所有的命令都將執行。

當程式出問題時,這些流控制運算子使得在命令中處理出錯和通知我們變得更有效率。我直接在命令列中使用它們,也在指令碼中使用。

你可以以 root 使用者的身份來刪除這個目錄和它裡面的內容。

[root@studentvm1 ~]# rm -rf /home/student/testdir

你是怎樣使用 Bash 控制運算子的呢?在評論區中告訴我們。