国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > Linux Shell > 正文

十三個(gè)寫好shell腳本的技巧分享

2020-07-27 18:48:11
字體:
供稿:網(wǎng)友

前言

產(chǎn)品的最終用戶通常不懂技術(shù),所以不管你怎么折騰產(chǎn)品代碼都無所謂。但腳本代碼不一樣,它們是開發(fā)人員寫給開發(fā)人員的。

有多少次,你運(yùn)行./script.sh,然后輸出一些東西,但卻不知道它剛剛都做了些什么。這是一種很糟糕的腳本用戶體驗(yàn)。我將在這篇文章中介紹如何寫出具有良好開發(fā)者體驗(yàn)的 shell 腳本。

產(chǎn)品的最終用戶通常不懂技術(shù),所以不管你怎么折騰產(chǎn)品代碼都無所謂。但腳本代碼不一樣,它們是開發(fā)人員寫給開發(fā)人員的。

這樣會(huì)導(dǎo)致一些問題:

  • 混亂的腳本――我知道,我們都是工程師,讀得懂代碼,但即使這樣,也請為我們這些對(duì) Shell 腳本不是很熟練的人考慮一下(我們在寫代碼時(shí)也會(huì)為你們考慮的)。
  • 滿屏的日志和錯(cuò)誤輸出――就算我們也是工程師,并不代表我們了解你所做的一切。
  • 弄得一團(tuán)糟卻沒有做好清理工作――是的,我們可以順著你的腳本手動(dòng)撤銷變更,但你真的會(huì)讓那些信任你的腳本的人這么做嗎?

所以,我們可以通過一些方法來為自己和別人寫出更好的 shell 腳本。這里給出的所有示例都可以使用與 POSIX 標(biāo)準(zhǔn)兼容的 shell 運(yùn)行(#!/bin/sh),因?yàn)樗亲畛S玫摹O游恼绿L了可以只看以下總結(jié)部分:

  • 提供--help標(biāo)記
  • 檢查所有命令的可用性
  • 獨(dú)立于當(dāng)前工作目錄
  • 如何讀取輸入:環(huán)境變量 vs. 標(biāo)記
  • 打印對(duì)系統(tǒng)執(zhí)行的所有操作
  • 如果有必要,提供--silent選項(xiàng)
  • 重新開啟顯示
  • 用動(dòng)畫的方式顯示進(jìn)度
  • 用顏色編碼輸出
  • 出現(xiàn)錯(cuò)誤立即退出腳本
  • 自己執(zhí)行清理工作
  • 在退出時(shí)使用不同的錯(cuò)誤碼
  • 在結(jié)束時(shí)打印一個(gè)新行

有時(shí)間的話可以接著往下看具體內(nèi)容:

提供--help標(biāo)記

安裝在系統(tǒng)上的二進(jìn)制文件通常帶有man幫助文檔,但對(duì)于腳本來說就不一定了。因此我們通常需要為腳本提供-h或--help標(biāo)記來打印有關(guān)如何使用腳本的信息。如果其他工程師需要修改腳本,這也可以作為腳本的內(nèi)聯(lián)文檔:

#!/bin/shif [ ${#@} -ne 0 ] && [ "${@#"--help"}" = "" ]; then printf -- '...help.../n'; exit 0;fi;

這段腳本先計(jì)算參數(shù)長度(${#@} -ne 0),只有當(dāng)參數(shù)長度不為零時(shí)才會(huì)檢查--help標(biāo)記。下一個(gè)條件會(huì)檢查參數(shù)中是否存在字符串“--help” 。第一個(gè)條件是必需的,如果參數(shù)長度為零則不需要打印幫助信息。

檢查所有命令的可用性

腳本通常會(huì)調(diào)用其他腳本或二進(jìn)制文件。在調(diào)用可能不存在的命令時(shí),請先檢查它們是否可用。可以使用“command -v 二進(jìn)制文件名稱”來執(zhí)行此操作,看看它的退出代碼是否為零。如果命令不可用,可以告訴用戶應(yīng)該如何獲得這個(gè)二進(jìn)制文件:

#!/bin/sh_=$(command -v docker);if [ "$?" != "0" ]; then printf -- 'You don/'t seem to have Docker installed./n'; printf -- 'Get it: https://www.docker.com/community-edition/n'; printf -- 'Exiting with code 127.../n'; exit 127;fi;# ...

獨(dú)立于當(dāng)前工作目錄

從不同的目錄執(zhí)行腳本可能會(huì)發(fā)生錯(cuò)誤,這樣的腳本沒有人會(huì)喜歡。要解決這個(gè)問題,請使用絕對(duì)路徑(/path/to/something)和腳本的相對(duì)路徑(如下所示)。

可以使用dirname $0引用腳本的當(dāng)前路徑:

#!/bin/shCURR_DIR="$(dirname $0);"printf -- 'moving application to /opt/app.jar';mv "${CURR_DIR}/application.jar" /opt/app.jar;

如何讀取輸入:環(huán)境變量 vs. 標(biāo)記

腳本通過兩種方式接受輸入:環(huán)境變量和選項(xiàng)標(biāo)記(參數(shù))。根據(jù)經(jīng)驗(yàn),對(duì)于不影響腳本行為的值,可以使用環(huán)境變量,而對(duì)于可能觸發(fā)腳本不同流程的值,可以使用腳本參數(shù)。

不影響腳本行為的變量可能是訪問令牌和 ID 之類的東西:

#!/bin/sh# do thisexport AWS_ACCESS_TOKEN='xxxxxxxxxxxx';./provision-everything# and not./provisiong-everything --token 'xxxxxxxxxxx';

影響腳本行為的變量可能是需要運(yùn)行實(shí)例的數(shù)量、是異步還是同步運(yùn)行、是否在后臺(tái)運(yùn)行等參數(shù):

#!/bin/sh# do this./provision-everything --async --instance-count 400# and notINSTANCE_COUNT=400 ASYNC=true ./provision-everything

打印對(duì)系統(tǒng)執(zhí)行的所有操作

腳本通常會(huì)對(duì)系統(tǒng)執(zhí)行有狀態(tài)的更改。不過,由于我們不知道用戶何時(shí)會(huì)向發(fā)送SIGINT,也不知道腳本錯(cuò)誤何時(shí)可能導(dǎo)致腳本意外終止,因此很有必要將正在做的事情打印在終端上,這樣用戶就可以在不去查看腳本的情況下回溯這些步驟:

#!/bin/shprintf -- 'Downloading required document to ./downloaded... ';wget -o ./downloaded https://some.site.com/downloaded;printf -- 'Moving ./downloaded to /opt/downloaded...';mv ./downloaded /opt/;printf -- 'Creating symlink to /opt/downloaded...';ln -s /opt/downloaded /usr/bin/downloaded;

在必要時(shí)提供--silent選項(xiàng)

有些腳本是為了將其輸出傳給其他腳本。雖說腳本都應(yīng)該能夠單獨(dú)運(yùn)行,不過有時(shí)候也有必要讓它們把輸出結(jié)果傳給另一個(gè)腳本。可以利用stty -echo來實(shí)現(xiàn)--silent標(biāo)記:

#!/bin/shif [ ${#@} -ne 0 ] && [ "${@#"--silent"}" = "" ]; then stty -echo;fi;# ...# before point of intended output:stty +echo && printf -- 'intended output/n';# silence it again till end of scriptstty -echo;# ...stty +echo;exit 0;

重新開啟顯示

在使用stty -echo關(guān)閉腳本顯示之后,如果發(fā)生致命錯(cuò)誤,腳本將終止,而且不會(huì)恢復(fù)終端輸出,這樣對(duì)用戶來說是沒有意義的。可以使用trap來捕捉SIGINT和其他操作系統(tǒng)級(jí)別的信號(hào),然后使用stty echo打開終端顯示:

#!/bin/sherror_handle() { stty echo;}if [ ${#@} -ne 0 ] && [ "${@#"--silent"}" = "" ]; then stty -echo; trap error_handle INT; trap error_handle TERM; trap error_handle KILL; trap error_handle EXIT;fi;# ...

用動(dòng)畫的方式顯示進(jìn)度

有些命令需要運(yùn)行很長時(shí)間,并非所有腳本都提供了進(jìn)度條。在用戶等待異步任務(wù)完成時(shí),可以通過一些方式告訴他們腳本仍在運(yùn)行。比如在while循環(huán)中打印一些信息:

#!/bin/shprintf -- 'Performing asynchronous action..';./trigger-action;DONE=0;while [ $DONE -eq 0 ]; do ./async-checker; if [ "$?" = "0" ]; then DONE=1; fi; printf -- '.'; sleep 1;done;printf -- ' DONE!/n';

或者可以做一些更好玩的小玩意兒,比如 http://mywiki.wooledge.org/BashFAQ/034。

用顏色編碼輸出

在腳本中調(diào)用其他二進(jìn)制文件或腳本時(shí),對(duì)它們的輸出進(jìn)行顏色編碼,這樣就可以知道哪個(gè)輸出來自哪個(gè)腳本或二進(jìn)制文件。這樣我們就不需要在滿屏的黑白輸出文本中查找想要的輸出結(jié)果。

理想情況下,腳本應(yīng)該輸出白色(默認(rèn)的,前臺(tái)進(jìn)程),子進(jìn)程應(yīng)該使用灰色(通常不需要,除非出現(xiàn)錯(cuò)誤),使用綠色表示成功,紅色表示失敗,黃色表示警告。

#!/bin/shprintf -- 'doing something... /n';printf -- '/033[37m someone else's output /033[0m/n';printf -- '/033[32m SUCCESS: yay /033[0m/n';printf -- '/033[33m WARNING: hmm /033[0m/n';printf -- '/033[31m ERROR: fubar /033[0m/n';

可以使用/033[Xm,其中X代表顏色代碼。有些腳本使用/e而不是/033,但要注意/e不適用于所有的 UNIX 系統(tǒng)。

正確示范

可在.sh 中使用的所有顏色和修飾符 https://misc.flogisoft.com/bash/tip_colors_and_formatting。

出現(xiàn)錯(cuò)誤立即退出腳本

set -e表示從當(dāng)前位置開始,如果出現(xiàn)任何錯(cuò)誤都將觸發(fā)EXIT。相反,set +e表示不管出現(xiàn)任何錯(cuò)誤繼續(xù)執(zhí)行腳本。

如果腳本是有狀態(tài)的(每個(gè)后續(xù)步驟都依賴前一個(gè)步驟),那么請使用set -e,在腳本出現(xiàn)錯(cuò)誤時(shí)立即退出腳本。如果要求所有命令都要執(zhí)行完(很少會(huì)這樣),那么就使用set +e。

#!/bin/shset +e;./script-1;./script-2; # does not depend on ./script-1./script-3; # does not depend on ./script-2set -e;./script-4;./script-5; # depends on success of ./script-4# ...

自己執(zhí)行清理工作

大多數(shù)腳本在出現(xiàn)錯(cuò)誤時(shí)不會(huì)執(zhí)行清理工作,能夠做好這方面工作的腳本實(shí)屬罕見,但這樣做其實(shí)很有用,還可以省下不少時(shí)間。前面已經(jīng)給出過示例,讓stty恢復(fù)正常,并借助trap命令來執(zhí)行清理工作:

#!/bin/shhandle_exit_code() { ERROR_CODE="$?"; printf -- "an error occurred. cleaning up now... "; # ... cleanup code ... printf -- "DONE./nExiting with error code ${ERROR_CODE}./n"; exit ${ERROR_CODE};}trap "handle_exit_code" EXIT;# ... actual script...

在退出時(shí)使用不同的錯(cuò)誤碼

在絕大多數(shù) shell 腳本中,exit 0 表示執(zhí)行成功,exit 1 表示發(fā)生錯(cuò)誤。對(duì)錯(cuò)誤與錯(cuò)誤碼進(jìn)行一對(duì)一的映射,這樣有助于腳本調(diào)試。

#!/bin/sh# ...if [ "$?" != "0" ]; then printf -- 'X happened. Exiting with status code 1./n'; exit 1;fi;# ...if [ "$?" != "0" ]; then printf -- 'Y happened. Exiting with status code 2./n'; exit 2;fi;

這樣做有另一個(gè)額外的好處,就是其他腳本在調(diào)用你的腳本時(shí),可以根據(jù)錯(cuò)誤碼來判斷發(fā)生了什么錯(cuò)誤。

在結(jié)束時(shí)打印一個(gè)新行

如果你有在遵循腳本的最佳實(shí)踐,那么可能會(huì)使用printf代替echo(它在不同系統(tǒng)中的行為有所差別)。問題是printf在命令結(jié)束后不會(huì)自動(dòng)添加一個(gè)新行,導(dǎo)致控制臺(tái)看起來是這樣的:

看起來是多么的平淡

這樣一點(diǎn)也不酷,可以通過簡單的方式打印一個(gè)新行:

#!/bin/sh# ... your awesome script ...printf -- '/n';exit 0;

這樣就可以得到:

好多了哈

別人會(huì)感謝你這么做的。

總結(jié)  

這篇文章大致總結(jié)了一些簡單易用的技巧,讓 shell 腳本更易于調(diào)試和使用。

原文鏈接:https://codeburst.io/13-tips-tricks-for-writing-shell-scripts-with-awesome-ux-19a525ae05ae

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)武林網(wǎng)的支持。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 伊金霍洛旗| 重庆市| 泰宁县| 名山县| 德钦县| 小金县| 浪卡子县| 杭锦后旗| 延川县| 郴州市| 岑巩县| 离岛区| 陕西省| 浏阳市| 四会市| 紫金县| 理塘县| 南皮县| 杭锦后旗| 昭苏县| 连平县| 合水县| 洪泽县| 柘城县| 固安县| 阳城县| 迁安市| 余姚市| 江川县| 盱眙县| 乐亭县| 云阳县| 喜德县| 利辛县| 西丰县| 简阳市| 合阳县| 万山特区| 宕昌县| 绿春县| 浪卡子县|