1. 程式人生 > >寫出健壯的Bash指令碼

寫出健壯的Bash指令碼

許多人用shell指令碼完成一些簡單任務,而且變成了他們生命的一部分。不幸的是,shell指令碼在執行異常時會受到非常大的影響。在寫指令碼時將這類問題最小化是十分必要的。本文中我將介紹一些讓Bash指令碼變得健壯的技術。

使用set -u

你因為沒有對變數初始化而使指令碼崩潰過多少次?對於我來說,很多次。

  1. chroot=$1  
  2. ...  
  3. rm -rf $chroot/usr/share/doc 

如果上面的程式碼你沒有給引數就執行,你不會僅僅刪除掉chroot中的文件,而是將系統的所有文件都刪除。那你應該做些什麼呢?好在bash提供了set -u,當你使用未初始化的變數時,讓bash自動退出。你也可以使用可讀性更強一點的set -o nounset

  1. david% bash /tmp/shrink-chroot.sh   
  2. $chroot=   
  3. david% bash -u /tmp/shrink-chroot.sh   
  4. /tmp/shrink-chroot.sh: line 3: $1: unbound variable   
  5. david%   

使用set -e

你寫的每一個指令碼的開始都應該包含set -e。這告訴bash一但有任何一個語句返回非真的值,則退出bash。使用-e的好處是避免錯誤滾雪球般的變成嚴重錯誤,能儘早的捕獲錯誤。更加可讀的版本:set -o errexit

使用-e把你從檢查錯誤中解放出來。如果你忘記了檢查,bash會替你做這件事。不過你也沒有辦法使用$?

來獲取命令執行狀態了,因為bash無法獲得任何非0的返回值。你可以使用另一種結構:

  1. command   
  2. if [ "$?"-ne 0]; then echo "command failed"; exit 1; fi   

可以替換成:

  1. command || { echo "command failed"; exit 1; }   

或者使用:

  1. if ! command; then echo "command failed"; exit 1; fi  

如果你必須使用返回非0值的命令,或者你對返回值並不感興趣呢?你可以使用 command || true,或者你有一段很長的程式碼,你可以暫時關閉錯誤檢查功能,不過我建議你謹慎使用。

  1. set +e   
  2. command1   
  3. command2   
  4. set -e  

相關文件指出,bash預設返回管道中最後一個命令的值,也許是你不想要的那個。比如執行 false | true 將會被認為命令成功執行。如果你想讓這樣的命令被認為是執行失敗,可以使用 set -o pipefail

程式防禦 - 考慮意料之外的事

你的指令碼也許會被放到“意外”的賬戶下執行,像缺少檔案或者目錄沒有被建立等情況。你可以做一些預防這些錯誤事情。比如,當你建立一個目錄後,如果父目錄不存在,mkdir 命令會返回一個錯誤。如果你建立目錄時給mkdir命令加上-p選項,它會在建立需要的目錄前,把需要的父目錄創建出來。另一個例子是 rm 命令。如果你要刪除一個不存在的檔案,它會“吐槽”並且你的指令碼會停止工作。(因為你使用了-e選項,對吧?)你可以使用-f選項來解決這個問題,在檔案不存在的時候讓指令碼繼續工作。

準備好處理檔名中的空格

有些人從在檔名或者命令列引數中使用空格,你需要在編寫指令碼時時刻記得這件事。你需要時刻記得用引號包圍變數。

  1. if [ $filename = "foo" ];  

$filename變數包含空格時就會掛掉。可以這樣解決:

  1. if [ "$filename" = "foo" ];  

使用[email protected]變數時,你也需要使用引號,因為空格隔開的兩個引數會被解釋成兩個獨立的部分。

  1. david% foo() { for i in [email protected]; do echo $i; done }; foo bar "baz quux"   
  2. bar   
  3. baz   
  4. quux   
  5. david% foo() { for i in "[email protected]"; do echo $i; done }; foo bar "baz quux"   
  6. bar   
  7. baz quux  

我沒有想到任何不能使用"[email protected]"的時候,所以當你有疑問的時候,使用引號就沒有錯誤。

如果你同時使用find和xargs,你應該使用 -print0 來讓字元分割檔名,而不是換行符分割。

  1. david% touch "foo bar"   
  2. david% find | xargs ls   
  3. ls: ./foo: No such file or directory   
  4. ls: bar: No such file or directory   
  5. david% find -print0 | xargs -0 ls   
  6. ./foo bar  

設定的陷阱

當你編寫的指令碼掛掉後,檔案系統處於未知狀態。比如鎖檔案狀態、臨時檔案狀態或者更新了一個檔案後在更新下一個檔案前掛掉。如果你能解決這些問題,無論是刪除鎖檔案,又或者在指令碼遇到問題時回滾到已知狀態,你都是非常棒的。幸運的是,bash提供了一種方法,當bash接收到一個UNIX訊號時,執行一個命令或者一個函式。可以使用trap命令。

trap command signal [signal ...]

你可以連結多個訊號(列表可以使用kill -l獲得),但是為了清理殘局,我們只使用其中的三個:INTTERMEXIT。你可以使用-as來讓traps恢復到初始狀態。

訊號描述

INT

Interrupt - 當有人使用Ctrl-C終止指令碼時被觸發

TERM

Terminate - 當有人使用kill殺死指令碼程序時被觸發

EXIT

Exit - 這是一個偽訊號,當指令碼正常退出或者set -e後因為出錯而退出時被觸發

當你使用鎖檔案時,可以這樣寫:

  1. if [ ! -e $lockfile ]; then   
  2. touch $lockfile   
  3. critical-section   
  4. rm $lockfile   
  5. else   
  6. echo "critical-section is already running"   
  7. fi  

當最重要的部分(critical-section)正在執行時,如果殺死了指令碼程序,會發生什麼呢?鎖檔案會被扔在那,而且你的指令碼在它被刪除以前再也不會運行了。解決方法:

  1. if [ ! -e $lockfile ]; then   
  2. trap " rm -f $lockfile; exit" INT TERM EXIT   
  3. touch $lockfile   
  4. critical-section   
  5. rm $lockfile   
  6. trap - INT TERM EXIT   
  7. else   
  8. echo "critical-section is already running"   
  9. fi  

相關推薦

健壯Bash指令碼

許多人用shell指令碼完成一些簡單任務,而且變成了他們生命的一部分。不幸的是,shell指令碼在執行異常時會受到非常大的影響。在寫指令碼時將這類問題最小化是十分必要的。本文中我將介紹一些讓Bash指令碼變得健壯的技術。 使用set -u 你因為沒有對變數

健壯的js程式碼

程式碼寫的好並不容易,做web開發一年了,一直寫js都是比較的鬆散,總覺得很亂,沒有什麼邏輯性,程式碼的健壯性也不高 這裡說說如何把js程式碼的健壯性提升起來 1. 就是對引數進行校驗,自己寫的函式傳遞進來的引數一定需要做校驗處理,js程式就有可能帶病執行,這和php

如何安全的、基本功能完善的Bash指令碼

每個人或多或少總會碰到要使用並且自己完成編寫一個最基礎的Bash指令碼的情況。真實情況是,沒有人會說“哇哦,我喜歡寫這些指令碼”。所以這也是為什麼很少有人在寫的時候專注在這些指令碼上。 我本身也不是一個Bash指令碼專家,但是我會在本文中跟你展示一個最基礎最簡單的安全指令碼模板,會讓你寫的Bash指令碼更加

shellcheck 幫助你更好的指令碼

簡介 shellcheck 是一款實用的 shell指令碼靜態檢查工具。 首先,可以幫助你提前發現並修復簡單的語法錯誤,節約時間。每次都需要執行才發現寫錯了一個小地方,確實非常浪費時間。 其次,可以針對你當前不夠完善不夠健壯的寫法,提供建議,幫助你提前繞開一些坑,避免等問題真的發生了才去除錯處理。 在其

docker~個容器啟動的bash指令碼

回到目錄 bash指令碼在linux裡就相當於win裡的bat和cmd及ps指令碼,可以把一般指令組織在一起,統一去執行,比如我有一些docker容器需要統一去啟動,這時,你可以把它們寫成一個bash指令碼,但有一點要注意,你的文件格式需要是unix,大家可以使用notepad++表寫指令碼,然後上傳到li

/etc/rc.d/init.d/functions 指令碼詳解【如何像紅帽一樣NB的啟動指令碼

以往寫伺服器啟動指令碼,關閉服務時,大多采用找PS-EF | GREP xxxx ,來 PID的方法,若執行成功,則echo .......... [ok],等等,總覺得不是很專業,,但凡看過REDHAT的啟動指令碼,他根本就沒這些字眼,那麼他是怎麼實現的呢? 看完下面這篇

指令碼一行echo也能bug ? glob瞭解一下

## 背景 最近處理一個 `bug` 很有意思,有客戶反饋某個配置檔案解析失敗了,出錯的那行的內容就只有一個字母 `a`。 最開始以為是誰改動了處理的指令碼,但要到了問題程式碼中的指令碼,比較發現跟庫上是一樣的。 又經過一番查詢,才發現原來是指令碼中的一行 `echo` 引入的。 ## 問題程式碼 出

老闆對我說,你要是能找公司裡摸魚的人,我就給你漲薪!於是我了兩個指令碼……

最近老闆沉迷於抖音,時不時在那邊呵呵傻笑,於是我偷偷湊過去一看,好傢伙,他正在看朱一旦~ ![](https://img2020.cnblogs.com/other/1218435/202005/1218435-20200516170614119-1793881256.gif) 這天,老闆幽幽地走到我身邊

【程式碼修煉系列分享】改掉這些壞習慣,還怕健壯的程式碼?(一)

Code Review 是一場苦澀但有意思的修行。 近期對團隊負責的專案,進行了一次 Code Review,程式碼評審過程中遇到的那些編碼壞習慣,笑的合不攏嘴。不過,評審中很多程式碼編寫問題,以往都多次提及過,所以還是按奈不住心中怒氣的小火苗。 作為用程式碼編寫人生的程式設計師,能擁有寫一手健壯程式碼的

【程式碼修煉系列分享】改掉這些壞習慣,還怕健壯的程式碼?(二)

Code Review 是一場苦澀但有意思的修行。書接上篇,本次繼續探討一下,該如何寫出健壯的程式碼? 一、編碼時:看似順眼,實則不然。 舉個栗子: String amount = request.getParameter("amount"); // 校驗金額小數點後最多兩位小數 BigDecimal a

小程序初體驗:手把手教你第一個小程序(一)

輸入框 個人 創建 公測 快速 nsh 成功 too 調用 本文筆者將根據quick start中的範例代碼,帶大家簡單地剖析一下小程序的運行方式,並介紹小程序開發中一些通用的特性,帶著大家一步步寫出自己的小程序。 適用對象:前端初學者,對小程序開發感興趣者 tip

威士忌與VR結合!飲酒者能自己的虛擬品酒筆記

get img mes 自己的 roman enter -i indent ros 原文標題:威士忌與VR結合!飲酒者能寫出自己的虛擬品酒筆記 VR體驗“Glenfiddich虛擬無限”將在世界各地的特定地方提供。 VR體驗將會讓用戶運送到蘇格蘭D

設計四個線程,當中共兩個線程每次對j添加1,另外兩個線程每次對j降低1。循環100次,程序。

public read 設計 test6 ng- -m popu div for package cn.usst.DataTest6; /** * 設計四個線程,當中共兩個線程每次對j添加1,另外兩個線程每次對j降低1。循環100次,寫出程序。 * @ * *

菜鳥,程序員,大師,神人 四個等級代碼的區別.

python 程序 lte and odin mat env math odi # !/usr/bin/env python# -*- coding: utf-8 -*-# 據說係菜鳥,程序員,大師,神人 四個等級寫出代碼的區別...import math as m#for

用shell或者python各種圖形

用shell或者python寫出各種圖形首先是shell等邊三角形[[email protected]/* */ my_script]# sh ff.sh num:6 * *** ***** ******* ********* *********** [[email&

怎樣才能高質量的偽原創,並且排名在前?

站長 拿站 索引 思考 總結 失去 讀取 新增 操作方法 1、等價替換法 ①、文字排序法:如隨便拿本站的這篇文章“編輯寫偽原創文章的五大技巧”如何做等價替換法?通過近義詞以及打亂標題關鍵詞順序來達到等價替換,你可以改成“編輯五大技巧寫偽原創文章”,“五大技巧幫助編輯寫偽原創

Python開發學習第一個Python程序

Python編程語言 Python開發學習 目標:了解Python,了解Python的特征,了解Python的應用,掌握Linux下Python開發環境的搭建,理解Windows下Python環境搭建,寫出第一個Python程序。 什麽是Python 一種解釋型的、面向對象的、帶有動態語義

4年前的隨筆---高質量程序的要點

找到 post 規範 ++ 總量 word popu 清晰 之前 從1990年開始敲代碼。到如今已經快20年了。總結出寫出高質量程序的幾個要點: - 1、開始寫之前思路越清晰完整越好。 - 2、寫的過程中代碼一定要規範一致,這種代碼便於維護和改動。這個規範一致性包括名稱

android:怎樣用一天時間,“飛機大戰”這種遊戲!(無框架-SurfaceView繪制)

col ride raw ech tro cti 開發人員 contex epo 序言作為一個android開發人員,時常想開發一個小遊戲娛樂一下大家,今天就說說,我是怎麽樣一天寫出一個簡單的“飛機大戰”的.體驗地址:http://www.wandoujia.com/ap

利用display屬性表格的布局樣式

title pad asc -m this 1.5 thead pop .text demo地址:http://codepen.io/tianzi77/pen/gpBzjy 元素結構: <h1>display構造的table小樣例