最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Linux Shell 腳本編程最佳實(shí)踐

2023-02-08 16:47 作者:泉來啦  | 我要投稿

前言

與其它的編碼規(guī)范一樣,這里所討論的不僅僅是編碼格式美不美觀的問題, 同時(shí)也討論一些約定及編碼標(biāo)準(zhǔn)。這份文檔主要側(cè)重于我們所普遍遵循的規(guī)則,對(duì)于那些不是明確強(qiáng)制要求的,我們盡量避免提供意見。

為什么要有編碼規(guī)范

編碼規(guī)范對(duì)于程序員而言尤為重要,有以下幾個(gè)原因:

  • 一個(gè)軟件的生命周期中,80%的花費(fèi)在于維護(hù)

  • 幾乎沒有任何一個(gè)軟件,在其整個(gè)生命周期中,均由最初的開發(fā)人員來維護(hù)

  • 編碼規(guī)范可以改善軟件的可讀性,可以讓程序員盡快而徹底地理解新的代碼

  • 如果你將源碼作為產(chǎn)品發(fā)布,就需要確任它是否被很好的打包并且清晰無誤,一如你已構(gòu)建的其它任何產(chǎn)品

  • 編碼規(guī)范原則

本文檔中的準(zhǔn)則致力于最大限度達(dá)到以下原則:

  • 正確性

  • 可讀性

  • 可維護(hù)性

  • 可調(diào)試性

  • 一致性

  • 美觀

盡管本文檔涵蓋了許多基礎(chǔ)知識(shí),但應(yīng)注意的是,沒有編碼規(guī)范可以為我們回答所有問題,開發(fā)人員始終需要再編寫完代碼后,對(duì)上述原則做出正確的判斷。

代碼規(guī)范等級(jí)定義

  • 可選(Optional):用戶可參考,自行決定是否采用;

  • 推薦(Preferable):用戶理應(yīng)采用,但如有特殊情況,可以不采用;

  • 必須(Mandatory):用戶必須采用(除非是少數(shù)非常特殊的情況,才能不采用);

:未明確指明的則默認(rèn)為必須(Mandatory)

主要參考如下文檔:

  • Google Shell Style Guide

  • Bash Hackers Wiki

源文件

基礎(chǔ)

使用場(chǎng)景

僅建議Shell用作相對(duì)簡(jiǎn)單的實(shí)用工具或者包裝腳本。因此單個(gè)shell腳本內(nèi)容不宜太過復(fù)雜。

在選擇何時(shí)使用shell腳本時(shí)時(shí)應(yīng)遵循以下原則:

  • 如主要用于調(diào)用其他工具且需處理的數(shù)據(jù)量較少,則shell是一個(gè)選擇

  • 如對(duì)性能十分敏感,則更推薦選擇其他語(yǔ)言,而非shell

  • 如需處理相對(duì)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),則更推薦選擇其他語(yǔ)言,而非shell

  • 如腳本內(nèi)容逐漸增長(zhǎng)且有可能出現(xiàn)繼續(xù)增長(zhǎng)的趨勢(shì),請(qǐng)盡早使用其他語(yǔ)言重寫

文件名

可執(zhí)行文件不建議有擴(kuò)展名,庫(kù)文件必須使用.sh作為擴(kuò)展名,且應(yīng)是不可執(zhí)行的。

執(zhí)行一個(gè)程序時(shí),無需知道其編寫語(yǔ)言,且shell腳本并不要求具有擴(kuò)展名,所以更傾向可執(zhí)行文件沒有擴(kuò)展名。

而庫(kù)文件知道其編寫語(yǔ)言十分重要,使用.sh作為特定語(yǔ)言后綴的擴(kuò)展名,可以和其他語(yǔ)言編寫的庫(kù)文件加以區(qū)分。

文件名要求全部小寫, 可以包含下劃線_或連字符-, 建議可執(zhí)行文件使用連字符,庫(kù)文件使用下劃線。

正例:

反例:

文件編碼

源文件編碼格式為UTF-8。避免不同操作系統(tǒng)對(duì)文件換行處理的方式不同,一律使用LF。

單行長(zhǎng)度

每行最多不超過120個(gè)字符。每行代碼最大長(zhǎng)度限制的根本原因是過長(zhǎng)的行會(huì)導(dǎo)致閱讀障礙,使得縮進(jìn)失效。

除了以下兩種情況例外:

  • 導(dǎo)入模塊語(yǔ)句

  • 注釋中包含的URL

如出現(xiàn)長(zhǎng)度必須超過120個(gè)字符的字符串,應(yīng)盡量使用here document或者嵌入的換行符等合適的方法使其變短。關(guān)注Linux中文社區(qū)

示例:

空白字符

除了在行結(jié)束使用換行符,空格是源文件中唯一允許出現(xiàn)的空白字符。

  • 字符串中的非空格空白字符,使用轉(zhuǎn)義字符

  • 不允許行前使用tab縮進(jìn),如果使用tab縮進(jìn),必須設(shè)置1個(gè)tab為4個(gè)空格

  • 不應(yīng)在行尾出現(xiàn)沒有意義的空白字符

垃圾清理(推薦)

對(duì)從來沒有用到的或者被注釋的方法、變量等要堅(jiān)決從代碼中清理出去,避免過多垃圾造成干擾。

結(jié)構(gòu)

使用bash

Bash 是唯一被允許使用的可執(zhí)行腳本shell。

可執(zhí)行文件必須以 #!/bin/bash開始。請(qǐng)使用set來設(shè)置shell的選項(xiàng),使得用bash <script_name>調(diào)用你的腳本時(shí)不會(huì)破壞其功能。

限制所有的可執(zhí)行shell腳本為bash使得我們安裝在所有計(jì)算機(jī)中的shell語(yǔ)言保持一致性。

正例:

反例:

許可證或版權(quán)信息(推薦)

許可證與版權(quán)信息需放在源文件的起始位置。例如:

縮進(jìn)

塊縮進(jìn)

每當(dāng)開始一個(gè)新的塊,縮進(jìn)增加4個(gè)空格(不能使用\t字符來縮進(jìn))。當(dāng)塊結(jié)束時(shí),縮進(jìn)返回先前的縮進(jìn)級(jí)別。縮進(jìn)級(jí)別適用于代碼和注釋。

管道

如果一行容不下整個(gè)管道操作,那么請(qǐng)將整個(gè)管道操作分割成每行一個(gè)管段。

如果一行容得下整個(gè)管道操作,那么請(qǐng)將整個(gè)管道操作寫在同一行,管道左右應(yīng)有空格。

否則,應(yīng)該將整個(gè)管道操作分割成每行一段,管道操作的下一部分應(yīng)該將管道符放在新行并且縮進(jìn)4個(gè)空格。這適用于管道符 | 以及邏輯運(yùn)算 ||&&。

正例:

反例:

循環(huán)

請(qǐng)將 ; do , ; then 和 while , for , if 放在同一行。

shell中的循環(huán)略有不同,但是我們遵循跟聲明函數(shù)時(shí)的大括號(hào)相同的原則。即:; do , ; then 應(yīng)該和 while/for/if 放在同一行。else 應(yīng)該單獨(dú)一行。結(jié)束語(yǔ)句應(yīng)該單獨(dú)一行且跟開始語(yǔ)句縮進(jìn)對(duì)齊。

正例:

反例:

case語(yǔ)句

通過4個(gè)空格縮進(jìn)可選項(xiàng)。可選項(xiàng)中的多個(gè)命令應(yīng)該被拆分成多行,模式表達(dá)式、操作和結(jié)束符 ;; 在不同的行。匹配表達(dá)式比 case 和 esac 縮進(jìn)一級(jí)。多行操作要再縮進(jìn)一級(jí)。模式表達(dá)式前面不應(yīng)該出現(xiàn)左括號(hào)。避免使用 ;& 和 ;;& 符號(hào)。示例:

只要整個(gè)表達(dá)式可讀,簡(jiǎn)單的單行命令可以跟模式和 ;; 寫在同一行。當(dāng)單行容不下操作時(shí),請(qǐng)使用多行的寫法。單行示例:

函數(shù)位置

將文件中所有的函數(shù)統(tǒng)一放在常量下面。不要在函數(shù)之間隱藏可執(zhí)行代碼。

如果你有函數(shù),請(qǐng)將他們統(tǒng)一放在文件頭部。只有includes, set 聲明和常量設(shè)置可能在函數(shù)聲明之前完成。不要在函數(shù)之間隱藏可執(zhí)行代碼。如果那樣做,會(huì)使得代碼在調(diào)試時(shí)難以跟蹤并出現(xiàn)意想不到的結(jié)果。

主函數(shù)main

對(duì)于包含至少了一個(gè)其他函數(shù)的足夠長(zhǎng)的腳本,建議定義一個(gè)名為 main 的函數(shù)。對(duì)于功能簡(jiǎn)單的短腳本, main函數(shù)是沒有必要的。

為了方便查找程序的入口位置,將主程序放入一個(gè)名為 main 的函數(shù)中,作為最底部的函數(shù)。這使其和代碼庫(kù)的其余部分保持一致性,同時(shí)允許你定義更多變量為局部變量(如果主代碼不是一個(gè)函數(shù)就不支持這種做法)。文件中最后的非注釋行應(yīng)該是對(duì) main 函數(shù)的調(diào)用:

注釋

代碼注釋的基本原則:

  • 注釋應(yīng)能使代碼更加明確

  • 避免注釋部分的過度修飾

  • 保持注釋部分簡(jiǎn)單、明確

  • 在編碼以前就應(yīng)開始寫注釋

  • 注釋應(yīng)說明設(shè)計(jì)思路而不是描述代碼的行為

  • 注釋與其周圍的代碼在同一縮進(jìn)級(jí)別,#號(hào)與注釋文本間需保持一個(gè)空格以和注釋代碼進(jìn)行區(qū)分。

文件頭

每個(gè)文件的開頭是其文件內(nèi)容的描述。除版權(quán)聲明外,每個(gè)文件必須包含一個(gè)頂層注釋,對(duì)其功能進(jìn)行簡(jiǎn)要概述。

例如:

功能注釋

主體腳本中除簡(jiǎn)潔明了的函數(shù)外都必須帶有注釋。庫(kù)文件中所有函數(shù)無論其長(zhǎng)短和復(fù)雜性都必須帶有注釋。

這使得其他人通過閱讀注釋即可學(xué)會(huì)如何使用你的程序或庫(kù)函數(shù),而不需要閱讀代碼。

所有的函數(shù)注釋應(yīng)該包含:

  • 函數(shù)的描述

  • 全局變量的使用和修改

  • 使用的參數(shù)說明

  • 返回值,而不是上一條命令運(yùn)行后默認(rèn)的退出狀態(tài)

例如:

TODO注釋

對(duì)那些臨時(shí)的, 短期的解決方案, 或已經(jīng)夠好但仍不完美的代碼使用 TODO 注釋.

TODO 注釋要使用全大寫的字符串 TODO, 在隨后的圓括號(hào)里寫上你的名字,郵件地址, bug ID, 或其它身份標(biāo)識(shí)和與這一 TODO 相關(guān)的 issue。主要目的是讓添加注釋的人 (也是可以請(qǐng)求提供更多細(xì)節(jié)的人) 可根據(jù)規(guī)范的TODO 格式進(jìn)行查找。添加 TODO 注釋并不意味著你要自己來修正,因此當(dāng)你加上帶有姓名的 TODO 時(shí), 一般都是寫上自己的名字。

這與C++ Style Guide中的約定相一致。

例如:

命名

函數(shù)名

使用小寫字母,并用下劃線分隔單詞。使用雙冒號(hào)::分隔包名。函數(shù)名之后必須有圓括號(hào)。

如果你正在寫單個(gè)函數(shù),請(qǐng)用小寫字母來命名,并用下劃線分隔單詞。如果你正在寫一個(gè)包,使用雙冒號(hào) :: 來分隔包名。函數(shù)名和圓括號(hào)之間沒有空格,大括號(hào)必須和函數(shù)名位于同一行。當(dāng)函數(shù)名后存在 () 時(shí),關(guān)鍵詞 function 是多余的,建議不帶 function 的寫法,但至少做到同一項(xiàng)目?jī)?nèi)風(fēng)格保持一致。

正例:

反例:

變量名

規(guī)則同函數(shù)名一致。

循環(huán)中的變量名應(yīng)該和正在被循環(huán)的變量名保持相似的名稱。示例:

常量和環(huán)境變量名

全部大寫,用下劃線分隔,聲明在文件的頂部。

常量和任何導(dǎo)出到環(huán)境中的變量都應(yīng)該大寫。示例:

有些情況下首次初始化及常量(例如,通過getopts),因此,在getopts中或基于條件來設(shè)定常量是可以的,但之后應(yīng)該立即設(shè)置其為只讀。值得注意的是,在函數(shù)中使用 declare 對(duì)全局變量無效,所以推薦使用 readonly 和 export 來代替。示例:

只讀變量

使用 readonly 或者 declare -r 來確保變量只讀。

因?yàn)槿肿兞吭趕hell中廣泛使用,所以在使用它們的過程中捕獲錯(cuò)誤是很重要的。當(dāng)你聲明了一個(gè)變量,希望其只讀,那么請(qǐng)明確指出。示例:

局部變量

每次只聲明一個(gè)變量,不要使用組合聲明,比如a=1 b=2;

使用 local 聲明特定功能的變量。聲明和賦值應(yīng)該在不同行。

必須使用 local 來聲明局部變量,以確保其只在函數(shù)內(nèi)部和子函數(shù)中可見。這樣可以避免污染全局名稱空間以及避免無意中設(shè)置可能在函數(shù)外部具有重要意義的變量。

當(dāng)使用命令替換進(jìn)行賦值時(shí),變量聲明和賦值必須分開。因?yàn)閮?nèi)建的 local 不會(huì)從命令替換中傳遞退出碼。正例:

反例:

異常與日志

異常

使用shell返回值來返回異常,并根據(jù)不同的異常情況返回不同的值。

日志

所有的錯(cuò)誤信息都應(yīng)被導(dǎo)向到STDERR,這樣將有利于出現(xiàn)問題時(shí)快速區(qū)分正常輸出和異常輸出。

建議使用與以下函數(shù)類似的方式來打印正常和異常輸出:

編程實(shí)踐(持續(xù)分類并完善)

變量擴(kuò)展(推薦)

通常情況下推薦為變量加上大括號(hào)如 "${var}" 而不是 "$var" ,但具體也要視情況而定。

以下按照優(yōu)先順序列出建議:

  • 與現(xiàn)有代碼保持一致

  • 單字符變量在特定情況下才需要被括起來

  • 使用引號(hào)引用變量,參考下一節(jié):變量引用

詳細(xì)示例如下:

正例:

變量引用(推薦)

變量引用通常情況下應(yīng)遵循以下原則:

  • 默認(rèn)情況下推薦使用引號(hào)引用包含變量、命令替換符、空格或shell元字符的字符串

  • 在有明確要求必須使用無引號(hào)擴(kuò)展的情況下,可不用引號(hào)

  • 字符串為單詞類型時(shí)才推薦用引號(hào),而非命令選項(xiàng)或者路徑名

  • 不要對(duì)整數(shù)使用引號(hào)

  • 特別注意 [[ 中模式匹配的引號(hào)規(guī)則

  • 在無特殊情況下,推薦使用 $@ 而非 $*

以下通過示例說明:

命令替換

使用 $(command) 而不是反引號(hào)。

因反引號(hào)如果要嵌套則要求用反斜杠轉(zhuǎn)義內(nèi)部的反引號(hào)。而 $(command) 形式的嵌套無需轉(zhuǎn)義,且可讀性更高。

正例:

反例:

條件測(cè)試

使用 [[ ... ]] ,而不是 [ , test , 和 /usr/bin/[ 。

因?yàn)樵?[[]] 之間不會(huì)出現(xiàn)路徑擴(kuò)展或單詞切分,所以使用 [[ ... ]] 能夠減少犯錯(cuò)。且 [[ ... ]] 支持正則表達(dá)式匹配,而 [ ... ] 不支持。參考以下示例:

字符串測(cè)試

盡可能使用變量引用,而非字符串過濾。

Bash可以很好的處理空字符串測(cè)試,請(qǐng)使用空/非空字符串測(cè)試方法,而不是過濾字符,讓代碼具有更高的可讀性。

正例:

反例:

正例:

反例:

正例:

反例:

文件名擴(kuò)展

當(dāng)進(jìn)行文件名的通配符擴(kuò)展時(shí),請(qǐng)指定明確的路徑。

當(dāng)目錄中有特殊文件名如以 - 開頭的文件時(shí),使用帶路徑的擴(kuò)展通配符 ./* 比不帶路徑的 * 要安全很多。

慎用eval

應(yīng)該避免使用eval。

Eval在用于分配變量時(shí)會(huì)修改輸入內(nèi)容,但設(shè)置變量的同時(shí)并不能檢查這些變量是什么。反例:

慎用管道連接 while 循環(huán)

請(qǐng)使用進(jìn)程替換或者for循環(huán),而不是通過管道連接while循環(huán)。

這是因?yàn)樵诠艿乐蟮膚hile循環(huán)中,命令是在一個(gè)子shell中運(yùn)行的,因此對(duì)變量的修改是不能傳遞給父shell的。

這種管道連接while循環(huán)中的隱式子shell使得bug定位非常困難。反例:

如果你確定輸入中不包含空格或者其他特殊符號(hào)(通常不是來自用戶輸入),則可以用for循環(huán)代替。例如:

使用進(jìn)程替換可實(shí)現(xiàn)重定向輸出,但是請(qǐng)將命令放入顯式子 shell,而非 while 循環(huán)創(chuàng)建的隱式子 shell。例如:

檢查返回值

總是檢查返回值,且提供有用的返回值。

對(duì)于非管道命令,使用 $? 或直接通過 if 語(yǔ)句來檢查以保持其簡(jiǎn)潔。

例如:

內(nèi)建命令和外部命令

當(dāng)內(nèi)建命令可以完成相同的任務(wù)時(shí),在shell內(nèi)建命令和調(diào)用外部命令之間,應(yīng)盡量選擇內(nèi)建命令。

因內(nèi)建命令相比外部命令而言會(huì)產(chǎn)生更少的依賴,且多數(shù)情況調(diào)用內(nèi)建命令比調(diào)用外部命令可以獲得更好的性能(通常外部命令會(huì)產(chǎn)生額外的進(jìn)程開銷)。

正例:

反例:

文件加載

加載外部庫(kù)文件不建議用使用.,建議使用source,已提升可閱讀性。

正例:

反例:

內(nèi)容過濾與統(tǒng)計(jì)

除非必要情況,盡量使用單個(gè)命令及其參數(shù)組合來完成一項(xiàng)任務(wù),而非多個(gè)命令加上管道的不必要組合。常見的不建議的用法例如:cat和grep連用過濾字符串; cat和wc連用統(tǒng)計(jì)行數(shù); grep和wc連用統(tǒng)計(jì)行數(shù)等。

正例:

反例:

正確使用返回與退出

除特殊情況外,幾乎所有函數(shù)都不應(yīng)該使用exit直接退出腳本,而應(yīng)該使用return進(jìn)行返回,以便后續(xù)邏輯中可以對(duì)錯(cuò)誤進(jìn)行處理。

正例:

反例:

附:常用工具

推薦以下工具幫助我們進(jìn)行代碼的規(guī)范:

  • ShellCheck


Linux Shell 腳本編程最佳實(shí)踐的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
稷山县| 安龙县| 年辖:市辖区| 荆门市| 疏附县| 仙居县| 嘉鱼县| 栾城县| 淳安县| 花垣县| 阜城县| 翁牛特旗| 吴桥县| 双辽市| 甘孜县| 和硕县| 腾冲县| 迭部县| 荣成市| 钦州市| 麻江县| 陵川县| 马边| 卢氏县| 辽阳县| 原阳县| 平塘县| 隆德县| 开封县| 茌平县| 揭阳市| 三门县| 馆陶县| 商水县| 邹城市| 罗山县| 济宁市| 宿州市| 勐海县| 微山县| 金湖县|