怎樣用 Bash 編程:語法和工具

怎樣用 Bash 編程:語法和工具

讓我們通過本系列文章來學習基本的 Bash 編程語法和工具,以及如何使用變量和控制運算符,這是三篇中的第一篇。-- David Both(作者)

Shell 是操作系統的命令解釋器,其中 Bash 是我最喜歡的。每當用戶或者系統管理員將命令輸入系統的時候,Linux 的 shell 解釋器就會把這些命令轉換成操作系統可以理解的形式。而執行結果返回 shell 程序後,它會將結果輸出到 STDOUT(標準輸出),默認情況下,這些結果會 顯示在你的終端 。所有我熟悉的 shell 同時也是一門編程語言。

Bash 是個功能強大的 shell,包含眾多便捷特性,比如:tab 補全、命令回溯和再編輯、別名等。它的命令行默認編輯模式是 Emacs,但是我最喜歡的 Bash 特性之一是我可以將其更改為 Vi 模式,以使用那些儲存在我肌肉記憶中的的編輯命令。

然而,如果你把 Bash 當作單純的 shell 來用,則無法體驗它的真實能力。我在設計一套包含三卷的 Linux 自學課程 時(這個系列的文章正是基於此課程),瞭解到許多 Bash 的知識,這些是我在過去 20 年的 Linux 工作經驗中所沒有掌握的,其中的一些知識就是關於 Bash 的編程用法。不得不說,Bash 是一門強大的編程語言,是一個能夠同時用於命令行和 shell 腳本的完美設計。

本系列文章將要探討如何使用 Bash 作為命令行界面(CLI)編程語言。第一篇文章簡單介紹 Bash 命令行編程、變量以及控制運算符。其他文章會討論諸如:Bash 文件的類型;字符串、數字和一些邏輯運算符,它們能夠提供代碼執行流程中的邏輯控制;不同類型的 shell 擴展;通過 for、while 和 until 來控制循環操作。

Shell

Bash 是 Bourne Again Shell 的縮寫,因為 Bash shell 是 基於 更早的 Bourne shell,後者是 Steven Bourne 在 1977 年開發的。另外還有很多 其他的 shell 可以使用,但下面四個是我經常見到的:

  • csh:C shell 適合那些習慣了 C 語言語法的開發者。
  • ksh:Korn shell,由 David Korn 開發,在 Unix 用戶中更流行。
  • tcsh:一個 csh 的變種,增加了一些易用性。
  • zsh:Z shell,集成了許多其他流行 shell 的特性。

所有 shell 都有內置命令,用以補充或替代核心工具集。打開 shell 的 man 說明頁,找到“BUILT-INS”那一段,可以查看都有哪些內置命令。

每種 shell 都有它自己的特性和語法風格。我用過 csh、ksh 和 zsh,但我還是更喜歡 Bash。你可以多試幾個,尋找更適合你的 shell,儘管這可能需要花些功夫。但幸運的是,切換不同 shell 很簡單。

所有這些 shell 既是編程語言又是命令解釋器。下面我們來快速瀏覽一下 Bash 中集成的編程結構和工具。

做為編程語言的 Bash

大多數場景下,系統管理員都會使用 Bash 來發送簡單明瞭的命令。但 Bash 不僅可以輸入單條命令,很多系統管理員可以編寫簡單的命令行程序來執行一系列任務,這些程序可以作為通用工具,能節省時間和精力。

編寫 CLI 程序的目的是要提高效率(做一個“懶惰的”系統管理員)。在 CLI 程序中,你可以用特定順序列出若干命令,逐條執行。這樣你就不用盯著顯示屏,等待一條命令執行完,再輸入另一條,省下來的時間就可以去做其他事情了。

什麼是“程序”?

自由在線計算機詞典( FOLDOC )對於程序的定義是:“由計算機執行的指令,而不是運行它們的物理硬件。”普林斯頓大學的 WordNet 將程序定義為:“……計算機可以理解並執行的一系列指令……” 維基百科 上也有一條不錯的關於計算機程序的條目。

總結下,程序由一條或多條指令組成,目的是完成一個具體的相關任務。對於系統管理員而言,一段程序通常由一系列的 shell 命令構成。Linux 下所有的 shell (至少我所熟知的)都有基本的編程功能,Bash 作為大多數 linux 發行版的默認 shell,也不例外。

本系列用 Bash 舉例(因為它無處不在),假如你使用一個不同的 shell 也沒關係,儘管結構和語法有所不同,但編程思想是相通的。有些 shell 支持某種特性而其他 shell 則不支持,但它們都提供編程功能。Shell 程序可以被存在一個文件中被反覆使用,或者在需要的時候才創建它們。

簡單 CLI 程序

最簡單的命令行程序只有一或兩條語句,它們可能相關,也可能無關,在按回車鍵之前被輸入到命令行。程序中的第二條語句(如果有的話)可能取決於第一條語句的操作,但也不是必須的。

這裡需要特別講解一個標點符號。當你在命令行輸入一條命令,按下回車鍵的時候,其實在命令的末尾有一個隱含的分號(;)。當一段 CLI shell 程序在命令行中被串起來作為單行指令使用時,必須使用分號來終結每個語句並將其與下一條語句分開。但 CLI shell 程序中的最後一條語句可以使用顯式或隱式的分號。

一些基本語法

下面的例子會闡明這一語法規則。這段程序由單條命令組成,還有一個顯式的終止符:

看起來不像一個程序,但它確是我學習每個新編程語言時寫下的第一個程序。不同語言可能語法不同,但輸出結果是一樣的。

讓我們擴展一下這段微不足道卻又無所不在的代碼。你的結果可能與我的有所不同,因為我的家目錄有點亂,而你可能是在 GUI 桌面中第一次登錄賬號。

現在是不是更明顯了。結果是相關的,但是兩條語句彼此獨立。你可能注意到我喜歡在分號前後多輸入一個空格,這樣會讓代碼的可讀性更好。讓我們再運行一遍這段程序,這次不要帶結尾的分號:

輸出結果沒有區別。

關於變量

像所有其他編程語言一樣,Bash 支持變量。變量是個象徵性的名字,它指向內存中的某個位置,那裡存著對應的值。變量的值是可以改變的,所以它叫“變~量”。

Bash 不像 C 之類的語言,需要強制指定變量類型,比如:整型、浮點型或字符型。在 Bash 中,所有變量都是字符串。整數型的變量可以被用於整數運算,這是 Bash 唯一能夠處理的數學類型。更復雜的運算則需要藉助 bc 這樣的命令,可以被用在命令行編程或者腳本中。

變量的值是被預先分配好的,這些值可以用在命令行編程或者腳本中。可以通過變量名字給其賦值,但是不能使用 $ 符開頭。比如,VAR=10 這樣會把 VAR 的值設為 10。要打印變量的值,你可以使用語句 echo $VAR。變量名必須以文本(即非數字)開始。

Bash 會保存已經定義好的變量,直到它們被取消掉。

下面這個例子,在變量被賦值前,它的值是空(null)。然後給它賦值並打印出來,檢驗一下。你可以在同一行 CLI 程序裡完成它:

注意:變量賦值的語法非常嚴格,等號(=)兩邊不能有空格。

那個空行表明了 MyVar 的初始值為空。變量的賦值和改值方法都一樣,這個例子展示了原始值和新的值。

正如之前說的,Bash 支持整數運算,當你想計算一個數組中的某個元素的位置,或者做些簡單的算術運算,這還是挺有幫助的。然而,這種方法並不適合科學計算,或是某些需要小數運算的場景,比如財務統計。這些場景有其它更好的工具可以應對。

下面是個簡單的算術題:

好像沒啥問題,但如果運算結果是浮點數會發生什麼呢?

結果會被取整。請注意運算被包含在 echo 語句之中,其實計算在 echo 命令結束前就已經完成了,原因是 Bash 的內部優先級。想要了解詳情的話,可以在 Bash 的 man 頁面中搜索 “precedence”。

控制運算符

Shell 的控制運算符是一種語法運算符,可以輕鬆地創建一些有趣的命令行程序。在命令行上按順序將幾個命令串在一起,就變成了最簡單的 CLI 程序:

只要不出錯,這些命令都能順利執行。但假如出錯了怎麼辦?你可以預設好應對出錯的辦法,這就要用到 Bash 內置的控制運算符, && 和 ||。這兩種運算符提供了流程控制功能,使你能改變代碼執行的順序。分號也可以被看做是一種 Bash 運算符,預示著新一行的開始。

&& 運算符提供瞭如下簡單邏輯,“如果 command1 執行成功,那麼接著執行 command2。如果 command1 失敗,就跳過 command2。”語法如下:

現在,讓我們用命令來創建一個新的目錄,如果成功的話,就把它切換為當前目錄。確保你的家目錄(~)是當前目錄,先嚐試在 /root 目錄下創建,你應該沒有權限:

上面的報錯信息是由 mkdir 命令拋出的,因為創建目錄失敗了。&& 運算符收到了非零的返回碼,所以 cd 命令就被跳過,前者阻止後者繼續運行,因為創建目錄失敗了。這種控制流程可以阻止後面的錯誤累積,避免引發更嚴重的問題。是時候講點更復雜的邏輯了。

當一段程序的返回碼大於零時,使用 || 運算符可以讓你在後面接著執行另一段程序。簡單語法如下:

解讀一下,“假如 command1 失敗,執行 command2”。隱藏的邏輯是,如果 command1 成功,跳過 command2。下面實踐一下,仍然是創建新目錄:

正如預期,因為目錄無法創建,第一條命令失敗了,於是第二條命令被執行。

把 && 和 || 兩種運算符結合起來才能發揮它們的最大功效。請看下面例子中的流程控制方法:

語法解釋:“假如 command1 退出時返回碼為零,就執行 command2,否則執行 command3。”用具體代碼試試:

現在我們再試一次,用你的家目錄替換 /root 目錄,你將會有權限創建這個目錄了:

像 command1 && command2 這樣的控制語句能夠運行的原因是,每條命令執行完畢時都會給 shell 發送一個返回碼,用來表示它執行成功與否。默認情況下,返回碼為 0 表示成功,其他任何正值表示失敗。一些系統管理員使用的工具用值為 1 的返回碼來表示失敗,但其他很多程序使用別的數字來表示失敗。

Bash 的內置變量 $? 可以顯示上一條命令的返回碼,可以在腳本或者命令行中非常方便地檢查它。要查看返回碼,讓我們從運行一條簡單的命令開始,返回碼的結果總是上一條命令給出的。

在這個例子中,返回碼為零,意味著命令執行成功了。現在對 root 的家目錄測試一下,你應該沒有權限:

本例中返回碼是 2,表明非 root 用戶沒有權限進入這個目錄。你可以利用這些返回碼,用控制運算符來改變程序執行的順序。

總結

本文將 Bash 看作一門編程語言,並從這個視角介紹了它的簡單語法和基礎工具。我們學習瞭如何將數據輸出到 STDOUT,怎樣使用變量和控制運算符。在本系列的下一篇文章中,將會重點介紹能夠控制指令執行流程的邏輯運算符。


via: https://opensource.com/article/19/10/programming-bash-part-1

作者: David Both 選題: lujun9972 譯者: jdh8383 校對: wxy

本文由 LCTT 原創編譯, Linux中國 榮譽推出


分享到:


相關文章: