Zsh 開發指南(第二十篇 代碼風格)

導讀

由於 shell 腳本語法比較靈活,寫 shell 腳本的開發者熟悉的編程語言也有較大差別,你們很容易寫出風格迥異的代碼出來。若是隻有本身一我的用還好,若是是你們合做開發同一個項目,代碼風格不一樣就會形成不小的麻煩。因此約定一個代碼風格是頗有必要的。git

本文中的代碼風格約定只是個人我的建議,能夠根據本身的需求或者喜愛來調整。本文的代碼風格約定,在必定程度上也適用於 bash。github

注意須要有豐富 shell 編程經驗的人制定和維護代碼風格約定,否則很容易沒法執行或者流於形式而解決不了實際問題。代碼風格約定不僅須要約定代碼怎麼寫,並且要說明爲何要這麼寫,否則容易由於難以服衆而沒法推廣。shell

縮進

  • 統一使用 4 個空格來縮進。

緣由:編程

  1. 要用空格而不是 tab。由於在終端上 cat less diff 等命令都將 tab 顯示成 8 個空格的寬度,有些命令是不可配置的(即便可配置,要讓全部機器配置同步也是件麻煩的事情)。若是本身在編輯器上配置 tab 爲 4 個或者 2 個空格,那麼就會和 cat less 等命令的顯示方法不一致,會致使不少麻煩。
  2. 8 個空格太長,縮進幾回就會致使行太長,而 shell 腳本每行不宜過長。
  3. 2 個空格的話,若是縮進比較頻繁,看起來比較費勁。另外若是寫代碼時不當心多了或者少了一個空格,在某些場景,不看邏輯的話,就沒法肯定是多個一個仍是少了一個,更容易致使他人錯誤的修改,或者代碼越改越亂。
  4. 對於 4 個空格也可能致使縮進層數多時行太長的問題,經過修改邏輯減小縮進層數或者折行的方法,而不是減小縮進的空格數量來解決。

每行代碼最多字符數

  • 非特殊場景,每行代碼不超過 100 個字符。

緣由:數組

  1. 代碼過長,閱讀起來不方便,用 diff 之類工具對代碼進行分析處理也不方便,因此須要約定最長字符數。
  2. 經典的 80 個字符的約定,是受當時的輸出設備限制而產生的標準,而如今的屏幕基本都是寬屏的,終端模擬器也都是可調大小的(而不是固定的 80x24)不必削足適履迎合陳舊的標準,浪費屏幕空間。並且若是使用 80 個字符的約定,很容易遇到須要折行的狀況,反而會致使可讀性降低。
  3. 若是一行超過了 100 個字符,一般說明邏輯太多,須要分行或者折行。
  4. 某些特殊場景,好比顯示一個 ASCII 字符組成的圖片,會有一行超過 100 個字符的需求,全部不能嚴格執行每行必須不超過 100 個字符的約定。若是分行或者折行會不可避免地致使代碼可讀性降低,那麼優先考慮可讀性。

折行

  • 在前一行尾部加一個空格和 \ 折行,折行後縮進一層(4 個空格)。
  • 若是縮進的是一個文本塊,可使用對齊縮進,也可使用 4 個空格的固定縮進。
  • 若是是在 aa && bb || cc[[ ]] 或者 (( )) 中折行,&& || 放在下一行的行首。

緣由:bash

  1. 折行的縮進和普通的縮進都是爲了體現代碼的遞進關係,不必區分對待(好比折行縮進兩層)。
  2. 若是爲了看起來美觀,使用對齊縮進而不是固定縮進。那麼由於每一個人的審美不一樣,很容易產生不一樣的縮進方法,從而產生沒必要要的麻煩。但對文本塊來講比較特殊,由於一般對齊縮進不會產生爭議。
  3. &&|| 在邏輯上屬於後半個語句,在天然語言中也是這樣,好比 明天我去公園或者去逛街,若是須要拆成兩個子句,那麼會是 明天我去公園,或者去逛街,而不是 明天我去公園或者,去逛街。對代碼來講也是同樣。並且把 &&|| 放在行首更容易對齊,看起來更舒服。

空格

  • 在縮進和對齊以外的場景,不容許出現邏輯上沒必要要的連續多個空格。
  • + && | 等雙元運算符左右要加一個空格。
  • ! ~等一元運算符和做用對象之間不加空格。
  • ( )(( )) { } 內側不加空格,[[ ]] 由於語法須要,內側加一個空格。
  • ; 以前不加空格,以後加一個空格。
  • 定義函數時(以及在 (( )) 中調用函數時),函數名和 ( 之間不加空格。
  • if while 等關鍵字和後邊的內容之間加一個空格。
  • if [[ ]] { 等場景中,{ 和前邊的內容之間加一個空格。
  • 變量和 [ ] 之間不加空格,用 [ ] 取數組或者哈希表值時,[ ] 內側不加空格。
  • > < 等重定向符號和文件或者文件描述符之間不加空格。

緣由:微信

  1. 適量地添加空格可讓代碼更清晰易讀。
  2. 這些約定基本屬於不少編程語言代碼風格中約定成俗的習慣,符合多數人的審美。

空行

  • 非特殊場景,不容許出現超過兩個連續空行。
  • #!/bin/zsh 後加一個空行。
  • if while 等語句塊以後加一個空行。
  • 定義函數後加一個空行。
  • 邏輯關係不強的兩行(或者兩塊)代碼之間,根據邏輯關係強弱(自行判斷),加一個或兩個空行。

緣由:less

  1. 適量添加空格,可讓代碼邏輯按照空行分隔,提升可讀性。
  2. 由於添加空行的方法涉及諸多因素,很難詳細約定,主要靠開發者自行判斷。

括號

  • 在判斷條件的場景,不使用 [ ],用 [[ ]] 代替。
  • 在數值計算的場景,使用 $(( )) 而不是 $[ ]

緣由:編程語言

  1. 在判斷條件的場景,[ ] 的功能沒有 [[ ]] 豐富,並且兩者的用法存在差別,混合使用容易出問題。
  2. 在數值比較或者計算的場景,$[ ] 的功能沒有 $(( )) 豐富,混合使用容易出問題。
  3. [ ] 在各類地方功能不一致,非必要場景儘可能避免使用。

常量

  • 字符串常量中若是沒有特殊符號,兩端能夠不加引號,也能夠加引號。
  • 使用數值時,兩端不加引號。

緣由:編輯器

  1. 若是任何字符串常量兩端都加引號,容易讓代碼中充斥着引號,影響可讀性。而且若是不當心誤刪引號,容易致使難以定位錯誤。
  2. shell 腳本和不少其餘編程語言不一樣,處理字符串的邏輯佔很大部分,每一個字符串常量兩邊都加引號的話,會增長不少額外工做量。

變量

  • $var 取變量值時,兩邊不加雙引號,除非須要將非字符串變量轉換成字符串。
  • 在非必須場景,不須要加 ${var} 中的大括號。
  • 變量使用前要明確指明是局部變量(用 local 定義)仍是全局變量(用 typeset -g 定義)。
  • 能用局部變量的地方所有使用局部變量(用 local 定義)。
  • 變量名中的單詞可使用下劃線分隔或者駝峯風格,在不影響可讀性的狀況也可使用全小寫字母,但在同一個文件中要一致。

緣由:

  1. 和 bash 不一樣,zsh 在使用 $var 讀取變量內容時,不用由於變量不存在、值爲空、包含特殊符號而產生各類邏輯錯誤,因此無需在兩端加雙引號。
  2. $var 讀變量是不少編程語言都有的用法,而 ${var} 幾乎是 shell 中特有的用法,而且輸入更麻煩,不必推廣這種用法。並且由於不加大括號致使變量名粘連而出錯的狀況,編寫代碼時便可識別出來,和外部輸入無關,不須要爲了不不存在的問題而輸入不少額外的大括號。
  3. 若是不指明變量是全局變量仍是局部變量,默認是全局變量,有時候很難簡單地判斷一個變量是做爲全局變量仍是局部變量使用的,這樣會給腳本的維護者帶來不少麻煩。
  4. 若是能使用局部變量的地方使用全局變量,更容易出現全局變量重名而互相影響致使錯誤的狀況。這種錯誤是很難排查的(由於不會產生語法錯誤,容易讓人懷疑是代碼邏輯的問題,而不去檢查是否有全局變量重名的狀況),每每會浪費開發或者測試人員大量的時間。
  5. 不一樣編程語言的開發者對變量名的風格偏好不一樣,不宜規定統一風格。

引號

  • 字符串常量兩端能夠添加雙引號或者單引號,但同一個文件中風格要一致。

緣由:

  1. 雙引號和單引號的功能不一樣,混合使用是不可避免的。
  2. 在雙引號和單引號都適用的場景,統一使用一種引號,可讓代碼更整潔易讀。
  3. 編程語言背景不一樣的開發者,對單雙引號的偏好不一樣,不宜強行規定默認使用的引號。

函數

  • 可使用 name() 或者 function name() 定義函數,但同一個文件中風格要一致。

緣由:

  1. 若是約定統一使用 name() 定義函數,那麼沒有照顧 JavaScript 等編程語言開發者的習慣,並且 function 關鍵字有助於代碼的搜索。
  2. 若是約定統一使用 function name() 定義函數,須要額外輸入 9 個字符,而意義有限,投入比產出要大。

腳本行數

  • 非特殊場景,單個腳本文件不超過 1000 行。

緣由:

  1. 由於 shell 腳本的特性,單個腳本文件過長容易致使各類問題(好比全局變量互相影響)。1000 行代碼對於多數場景都夠用了。
  2. 若是寫的是安裝腳本之類須要分發的腳本,那麼分發單個文件要比分發多個文件(須要打包解包等額外工做)容易不少,這種場景可能須要寫長腳本。因此不宜強行規定單個腳本文件最大行數。

語句風格

  • 條件、循環、選擇等語句,可使用本系列教程中的風格,也可使用 POSIX shell 風格,但同一個文件的風格要一致。

緣由:

  1. 本系列教程的中語句風格簡潔易懂,而且和 c、Java、JavaScript 等語言的語句風格相近。
  2. 從 bash 遷移過來的開發者習慣使用 POSIX shell 風格語句,須要兼顧。

本系列教程語句風格實例:

if [[ ... ]] {
} elif ((...)) {
} else {
}

case $i {
    (a)
    ...
    ;;

    (*)
    ...
    ;;
}複製代碼

POSIX shell 語句風格實例:

if [[ ... ]]; then
elif ((...)); then
else
fi

case $i in
    (a)
    ...
    ;;

    (*)
    ...
    ;;
esac複製代碼

總結

本文介紹了我建議的 zsh 代碼風格,能夠適當參考。

全系列文章地址:github.com/goreliu/zsh…

付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活訂價,歡迎諮詢,微信 ly50247。

相關文章
相關標籤/搜索