每個程序員都應(yīng)知道的五個 Bash 編碼技巧
Bash 無疑已經(jīng)成為每個現(xiàn)代類 Unix 系統(tǒng)或基于 Unix 的操作系統(tǒng)的本地內(nèi)置自動化解決方案。程序員使用 Bash 創(chuàng)建 Shell 腳本來自動化重復(fù)的命令行任務(wù)。Bash 的主要目標(biāo)是提供一種最小的語法來執(zhí)行其他程序并處理它們的退出代碼和輸出。但是,現(xiàn)代的 Bash 解釋器具有完整的命令語言,提供大多數(shù)通用編程語言的功能。因此,我們可以通過包含傳統(tǒng)的命令行調(diào)用和算法代碼編寫高度可讀的Shell腳本。現(xiàn)代的Bash版本引入了關(guān)聯(lián)數(shù)組和支持按引用傳遞的性能相關(guān)特性,使 Bash 具有與其他準(zhǔn)備好進行 Shell 腳本編寫的語言競爭的能力。
在本文中,我將介紹一些 Bash 編碼技巧,您可以在您的 Shell 腳本中包含它們,使它們現(xiàn)代化、快速和可讀。使用這些技巧,您可以使用 Bash 編寫通用編程或算法實現(xiàn),例如算法原型、實現(xiàn)實用程序,甚至是競爭編程!
在 Shell 腳本中使用數(shù)組
傳統(tǒng)的 Bash 變量通常沒有類型,但是您可以根據(jù)特定的處理上下文將其處理為整數(shù)、小數(shù)或字符串。我們通常使用Bash變量來存儲命令輸出、算法參數(shù)和其他臨時值。Bash還支持兩種數(shù)組類型:一維(按數(shù)字索引)和關(guān)聯(lián)(鍵值結(jié)構(gòu))。與其他流行的動態(tài)類型通用語言(例如Python、PHP 或 JavaScript)一樣,使用 Bash 數(shù)組非常容易。以下是如何在 Bash 中創(chuàng)建數(shù)組的方法:
以上代碼輸出的數(shù)組內(nèi)容如下:
您可以通過 declare 內(nèi)置命令檢查每個數(shù)組引用的聲明,如下所示:
在 Bash 中檢查數(shù)組聲明,作者的屏幕截圖 您還可以使用最小的語法進行數(shù)組操作和處理活動,例如追加新項、刪除現(xiàn)有項、處理數(shù)組元素、排序等。例如,以下代碼刪除無效的分?jǐn)?shù)值并打印前三個最高分?jǐn)?shù):
以上代碼會生成一個單獨的進程進行排序,因為我們使用了 sort 外部命令,但是您可以通過使用一些 Bash 代碼實現(xiàn)簡單的排序算法,例如選擇排序,來避免這種情況。
創(chuàng)建映射或字典
在一些編程場景中,我們需要在 shell 腳本中存儲鍵值對數(shù)據(jù)。程序員通常使用鍵值數(shù)據(jù)結(jié)構(gòu)來創(chuàng)建字典結(jié)構(gòu)、映射和緩存容器(通過記憶化)。如果您使用 Python 編寫您的 shell 腳本,您可以使用內(nèi)置的字典數(shù)據(jù)結(jié)構(gòu)來存儲鍵值數(shù)據(jù)。如何在 Bash 中使用字典結(jié)構(gòu)?
Bash 4.0 版本引入了關(guān)聯(lián)數(shù)組功能,用于存儲鍵值數(shù)據(jù)。下面是一個 Bash 關(guān)聯(lián)數(shù)組的簡單示例:
在這里,我們使用了 !mapvar[@] 語法來提取所有字典鍵作為數(shù)組進行迭代。上述代碼將打印出所有鍵和對應(yīng)的值,如下所示:
Bash 讓你可以使用最少的語法來操作和訪問關(guān)聯(lián)數(shù)組數(shù)據(jù)。使用Bash關(guān)聯(lián)數(shù)組的方式就像使用 Python 字典一樣。請看下面的例子:
以上源代碼向用戶請求x和y坐標(biāo),為缺失的坐標(biāo)軸值設(shè)置默認(rèn)值,并在終端上打印它們。在這里,我們使用! -v語法,因為通常我們使用 Python 字典中的 not in。
實現(xiàn)命名參數(shù)支持
當(dāng)您通過 Bash 解釋器執(zhí)行 shell 腳本時,操作系統(tǒng)會創(chuàng)建一個新的 Bash 進程,并將您的腳本文件作為第一個命令行參數(shù)。操作系統(tǒng)通常允許您將一系列參數(shù)傳遞給每個操作系統(tǒng)進程。當(dāng)您為其他命令/進程提供命令行參數(shù)時,您也可以將它們傳遞到您的 Bash 腳本中。假設(shè)您需要將兩個整數(shù)值傳遞給腳本。然后,您可以輕松使用 $1 和 $2 分別訪問第一個和第二個參數(shù)值。但是,當(dāng)您使用更多索引參數(shù)并且需要實現(xiàn)可選參數(shù)(也稱為命令行標(biāo)志或選項)時,事情將變得復(fù)雜。
作為這種情況的解決方案,您可以使用內(nèi)置的 getopts 來使用命名參數(shù)。使用以下 shell 腳本,我們可以覆蓋一些腳本中的默認(rèn)值:
默認(rèn)情況下,上面的腳本顯示一個帶有默認(rèn)標(biāo)題和消息的 GTK 消息框,但是您可以使用命名的命令行參數(shù)來覆蓋它們,如下所示:
getopts 內(nèi)置支持僅使用單個字母選項。您可以使用 getopt 來使用長形式選項(即–title),如此 gist 所示。
使用函數(shù)中的引用傳遞
引用傳遞是一種編程語言特性,它允許您通過內(nèi)存引用將數(shù)據(jù)傳遞到函數(shù)中,而不是將整個數(shù)據(jù)段復(fù)制到新變量中。C ++ 程序員總是努力編寫性能優(yōu)先的代碼,對于類對象,結(jié)構(gòu)體和字符串,使用引用傳遞而不是值傳遞。
如果您使用的是 Bash 4.3 或更新版本,則可以使用名稱引用在 shell 腳本中實現(xiàn)引用傳遞。以下是一個簡單的示例代碼片段,通過函數(shù)更改字符串變量:
上述 change_str_var 函數(shù)使用 local 命令創(chuàng)建一個局部的 str_ref 引用,引用全局的 str 變量。然后,它通過覆蓋舊字符串值來分配一個新的字符串值。
一些程序員在函數(shù)內(nèi)部使用 echo 命令,并通過命令替換特性調(diào)用特定函數(shù)以從 Bash 函數(shù)返回值(因為原生 Bash return 關(guān)鍵字僅支持返回有效的退出代碼)。這會生成另一個子 shell 并消耗更多資源。因此,現(xiàn)在程序員可以使用引用傳遞并編寫性能優(yōu)先的Bash函數(shù)返回,如果他們使用新的 Bash 版本。
使用類型和修飾符屬性的變量
Bash 被稱為一種無類型命令語言。換句話說,它通常將變量數(shù)據(jù)處理為字符串,但根據(jù)上下文(例如在算術(shù)擴展中)進行相應(yīng)處理。另一方面,Bash 也允許程序員使用類型屬性,并提供兩種內(nèi)置的數(shù)組類型。即使有了這些功能,我們也不能將 Bash 視為純動態(tài)類型語言,但這些變量屬性將Bash置于無類型和動態(tài)類型語言之間。
Bash 支持使用整數(shù)變量屬性將特定變量標(biāo)記為整數(shù)。一旦創(chuàng)建了一個整數(shù)變量,當(dāng)您分配非整數(shù)值時,Bash 會發(fā)出警告,如下所示:
Bash 還允許使用 declare -r 命令創(chuàng)建常量。每當(dāng)您的腳本嘗試更改常量時,Bash 會在屏幕上打印錯誤消息。此外,正如我們之前使用的那樣,您可以使用 declare 內(nèi)置函數(shù)創(chuàng)建數(shù)組。
Bash 還允許您為變量添加一些修飾符屬性。例如,您可以創(chuàng)建僅包含小寫字母或大寫字母的字符串,如下所示:
使用 Bash 變量屬性,您可以編寫更少出錯、更易讀、更現(xiàn)代的 shell 腳本。