一,背景
1.1 明确使用哪個Shell
Bash是唯一允許用于可執行檔案的shell腳本語言。
可執行檔案必須以 #!/bin/bash 開頭,并且使用最少的标志位。使用set指令設定shell選項,以便在将腳本作為bash script_name調用時不會破壞其功能。
将所有可執行shell腳本限制為bash,使我們擁有一種在所有計算機上都安裝的一緻的shell語言。
唯一的例外情況是你不得不為某些你在編寫代碼的環境中被迫使用的情況。其中一個例子是需要使用純Bourne shell執行腳本的Solaris SVR4軟體包。
1.2 何時使用Shell
Shell僅應用于小型實用工具或簡單的包裝腳本。
雖然shell腳本不是一種開發語言,但在Google的各種實用腳本編寫中會使用它。這個風格指南更多地是對其使用的一種承認,而不是建議廣泛部署。
二,一些準則:
如果大部分時間在調用其他實用工具,并且進行的資料操作相對較少,那麼shell是這項任務的可接受選擇。
如果性能很重要,使用除shell之外的其他工具。
如果你正在編寫的腳本超過100行,或者使用的控制流邏輯不直覺,那麼你應該現在就将其改寫為一種更結構化的語言。請記住,腳本會逐漸增長。及時地重寫你的腳本,以避免以後重寫需要花費更多時間。
在評估你的代碼複雜性(例如決定是否切換語言)時,請考慮代碼是否易于被除了作者以外的其他人維護。
2.1 Shell 檔案和解釋器調用
- 檔案擴充名
可執行檔案應該沒有擴充名(強烈推薦)或者使用 .sh 擴充名。庫檔案必須使用 .sh 擴充名但不可執行。
在執行程式時,不需要知道它是用哪種語言編寫的,而且 shell 不要求有擴充名,是以我們更傾向于不為可執行檔案使用擴充名。
然而,對于庫檔案來說,知道它所使用的語言很重要,并且有時候需要在不同語言中使用相似的庫。這允許具有相同目的但不同語言的庫檔案具有相同的檔案名,隻是語言特定字尾不同。
- SUID/SGID
在 shell 腳本中禁止使用 SUID 和 SGID。
由于 shell 存在太多安全問題,幾乎不可能通過足夠的方式來保證安全,是以禁止使用 SUID/SGID。雖然 bash 在執行 SUID 方面做得比較困難,但在某些平台上仍然可能實作,這就是為什麼我們明确禁止使用 SUID 的原因。
如果需要提供提升後的通路權限,請使用 sudo。
2.2 環境
- STDOUT vs STDERR
所有錯誤消息都應該發送到 STDERR。
這樣可以更容易地區分正常狀态和實際問題。
建議使用一個函數來列印錯誤消息和其他狀态資訊。
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
if ! do_something; then
err "Unable to do_something"
exit 1
fi
2.3 注釋
- 檔案頭
每個檔案都要以其内容的描述開始。
每個檔案必須有一個頂級注釋,其中包括對其内容的簡要概述。版權聲明和作者資訊可選擇性添加。
示例:
#!/bin/bash
#
# Perform hot backups of Oracle databases.
- 函數注釋
任何不明顯且不簡短的函數必須進行注釋。無論長度或複雜程度如何,庫中的任何函數都必須進行注釋。
通過閱讀注釋(以及提供的自助幫助,如果有的話),其他人應該能夠學習如何使用您的程式或使用您庫中的函數,而無需閱讀代碼。
所有函數注釋都應描述預期的 API 行為,包括:
函數的描述。
- 全局變量:使用和修改的全局變量清單。
- 參數:接受的參數。
- 輸出:輸出到 STDOUT 或 STDERR。
- 傳回值:除了最後一條運作指令的預設退出狀态之外的傳回值。
示例:
#######################################
# Cleanup files from the backup directory.
# Globals:
# BACKUP_DIR
# ORACLE_SID
# Arguments:
# None
#######################################
function cleanup() {
…
}
#######################################
# Get configuration directory.
# Globals:
# SOMEDIR
# Arguments:
# None
# Outputs:
# Writes location to stdout
#######################################
function get_dir() {
echo "${SOMEDIR}"
}
#######################################
# Delete a file in a sophisticated manner.
# Arguments:
# File to delete, a path.
# Returns:
# 0 if thing was deleted, non-zero on error.
#######################################
function del_thing() {
rm "$1"
}
- 實作注釋
在代碼中注釋那些棘手、不明顯、有趣或重要的部分。
這遵循了谷歌通常的編碼注釋實踐。不要對每個地方都進行注釋。如果有一個複雜的算法或者你正在做一些非正常的事情,請添加一個簡短的注釋。
- 待辦事項注釋
使用待辦事項注釋來标記臨時性的代碼、短期解決方案或者達到足夠好但不完美的代碼。
這符合 C++ Guide 中的約定。
待辦事項注釋應包括全大寫的 TODO 字元串,後面跟着問題所涉及的最佳上下文知識人員的姓名、電子郵件位址或其他辨別符。主要的目的是擁有一個一緻的待辦事項,可以通過搜尋來找到如何在請求時擷取更多詳細資訊。待辦事項并不意味着該人将修複問題。是以,當建立一個待辦事項時,幾乎總是使用你自己的姓名。
# TODO(mrmonkey): Handle the unlikely edge cases (bug ####)
專欄時間
通過學習專欄,您将能夠獲得以下收獲:
- 掌握 Shell 程式設計的核心概念和技巧:本專欄将深入淺出地講解 Shell 程式設計的核心概念和技巧,例如 Shell 腳本的文法、變量、流程控制、函數、檔案操作、正規表達式等,讓您能夠輕松掌握 Shell 程式設計的常用範式和技巧。
- 熟練使用 Shell 程式設計的最佳實踐和規範:本專欄将介紹 Shell 程式設計的最佳實踐和規範,例如命名規範、注釋規範、代碼結構規範等,讓您能夠編寫高效、可讀性強的 Shell 腳本,提高代碼的可維護性和可重用性。
- 提高 Shell 腳本的效率和性能:本專欄将介紹 Shell 程式設計的效率和性能優化技巧,例如并行化、緩存、優化算法和資料結構等,讓您的 Shell 腳本能夠更加高效地運作,提升系統的整體性能。
- 提高 Shell 腳本的健壯性和穩定性:本專欄将介紹 Shell 程式設計的異常處理和錯誤處理方法,例如使用 try-catch 語句、檢查錯誤碼、備份資料等,讓您的 Shell 腳本能夠更加健壯、穩定,避免因為異常情況導緻系統崩潰或資料丢失。
- 深入了解 Shell 程式設計的進階技巧和工具:本專欄将介紹 Shell 程式設計的進階技巧和工具,例如使用 awk、sed、grep、find 等工具進行文本處理、使用調試器進行調試、使用版本控制工具進行代碼管理等,讓您成為 Shell 程式設計的進階專家。
總之,通過學習本專欄,您将能夠深入掌握 Shell 程式設計的核心技能和最佳實踐,提高 Shell 程式設計的效率、可讀性、健壯性和可維護性,讓您在 Shell 程式設計領域成為技術的領軍者!