Bash指令碼中的set命令

2021-08-16 06:29:31 字數 4492 閱讀 8542

伺服器的開發和管理離不開 bash 指令碼,掌握它需要學習大量的細節。

set命令是 bash 指令碼的重要環節,卻常常被忽視,導致指令碼的安全性和可維護性出問題。本文介紹它的基本用法,讓你可以更安心地使用 bash 指令碼。

我們知道,bash 執行指令碼的時候,會建立乙個新的 shell。

$ bash script.sh
上面**中,script.sh是在乙個新的 shell 裡面執行。這個 shell 就是指令碼的執行環境,bash 預設給定了這個環境的各種引數。

set命令用來修改 shell 環境的執行引數,也就是可以定製環境。一共有十幾個引數可以定製,官方手冊有完整清單,本文介紹其中最常用的四個。

順便提一下,如果命令列下不帶任何引數,直接執行set,會顯示所有的環境變數和 shell 函式。

$ set
執行指令碼的時候,如果遇到不存在的變數,bash 預設忽略它。

#!/usr/bin/env bash

echo

$aecho bar

上面**中,$a是乙個不存在的變數。執行結果如下。

$ bash script.sh

bar

可以看到,echo $a輸出了乙個空行,bash 忽略了不存在的$a,然後繼續執行echo bar。大多數情況下,這不是開發者想要的行為,遇到變數不存在,指令碼應該報錯,而不是一聲不響地往下執行。set -u就用來改變這種行為。指令碼在頭部加上它,遇到不存在的變數就會報錯,並停止執行。

#!/usr/bin/env bash

set -u

echo

$aecho bar

執行結果如下

$ bash script.sh

bash: script.sh:行4: a: 未繫結的變數

可以看到,腳本報錯了,並且不再執行後面的語句。-u還有另一種寫法-o nounset,兩者是等價的。

set

-o nounset

預設情況下,指令碼執行後,螢幕只顯示執行結果,沒有其他內容。如果多個命令連續執行,它們的執行結果就會連續輸出。有時會分不清,某一段內容是什麼命令產生的。

set -x用來在執行結果之前,先輸出執行的那一行命令。

#!/usr/bin/env bash

set -x

echo bar

執行上面的指令碼,結果如下。

$ bash script.sh

+ echo bar

bar

可以看到,執行echo bar之前,該命令會先列印出來,行首以+表示。這對於除錯複雜的指令碼是很有用的。-x還有另一種寫法-o xtrace

set

-o xtrace

如果指令碼裡面有執行失敗的命令(返回值非0),bash 缺省會繼續執行後面的命令。

#!/usr/bin/env bash

fooecho bar

上面指令碼中,foo是乙個不存在的命令,執行時會報錯。但是,bash 會忽略這個錯誤,繼續往下執行。

$ bash script.sh

script.sh:行3: foo: 未找到命令

bar

可以看到,bash 只是顯示有錯誤,並沒有終止執行。這種行為很不利於指令碼安全和除錯。實際開發中,如果某個命令失敗,往往需要指令碼停止執行,防止錯誤累積。這時,一般採用下面的寫法。

command || exit

1# command是具體的命令

上面的寫法表示只要command有非零返回值,指令碼就會停止執行。如果停止執行之前需要完成多個操作,就要採用下面三種寫法。

# 寫法一

command ||

# 寫法二

if ! command; then

echo

"command failed"; exit

1; fi

# 寫法三

command

if [ "$?"

-ne0 ]; then

echo

"command failed"; exit

1; fi

另外,除了停止執行,還有一種情況。如果兩個命令有繼承關係,只有第乙個命令成功了,才能繼續執行第二個命令,那麼就要採用下面的寫法。

command1 && command2
上面這些寫法多少有些麻煩,容易疏忽。set -e從根本上解決了這個問題,它使得指令碼只要發生錯誤,就終止執行。

#!/usr/bin/env bash

set-e

fooecho bar

執行結果如下

$ bash script.sh

script.sh:行4: foo: 未找到命令

可以看到,第4行執行失敗以後,指令碼就終止執行了。

set -e根據返回值來判斷,乙個命令是否執行失敗。但是,某些命令的非零返回值可能不表示失敗,或者開發者希望在命令失敗的情況下,指令碼繼續執行下去。這時可以暫時關閉set -e,該命令執行結束後,再重新開啟set -e

set +e             # 關閉-e選項

command1

command2

set-e

# 重新開啟-e選項

還有一種方法是使用command || true,使得該命令即使執行失敗,指令碼也不會終止執行。

#!/bin/bash

set-e

foo || true

echo bar

上面**中,true使得這一行語句總是會執行成功,後面的echo bar會執行。-e還有另一種寫法-o errexit

set

-o errexit

set -e有乙個例外情況,就是不適用於管道命令。所謂管道命令,就是多個子命令通過管道運算子(|)組合成為乙個大的命令。bash 會把最後乙個子命令的返回值,作為整個命令的返回值。也就是說,只要最後乙個子命令不失敗,管道命令總是會執行成功,因此它後面命令依然會執行,set -e就失效了。請看下面這個例子。

#!/usr/bin/env bash

set-e

foo | echo a

echo bar

執行結果如下

$ bash script.sh

ascript.sh:行4: foo: 未找到命令

bar

上面**中,foo是乙個不存在的命令,但是foo | echo a這個管道命令會執行成功,導致後面的echo bar會繼續執行。set -o pipefail用來解決這種情況,只要乙個子命令失敗,整個管道命令就失敗,指令碼就會終止執行。

#!/usr/bin/env bash

set -eo pipefail

foo | echo a

echo bar

執行後,結果如下

$ bash script.sh

ascript.sh:行4: foo: 未找到命令

可以看到,echo bar沒有執行。

set命令的上面這四個引數,一般都放在一起使用。

# 寫法一

set -euxo pipefail

# 寫法二

set -eux

set -o pipefail

這兩種寫法建議放在所有 bash 指令碼的頭部。另一種辦法是在執行 bash 指令碼的時候,從命令列傳入這些引數。

$ bash -euxo pipefail script.sh

BASH指令碼基礎 使用set

這篇文章介紹一下在bash中使用set的方法。set可以用於設定指令碼的執行方式,指令碼啟動時也可以通過設定選項來進行設定。在指令碼啟動的設定中,常見的一些選項都可以通過set來進行設定,比如 設定選項 設定選項 快捷設定選項 設定說明 語法檢查 n 用來進行bash語法的檢查 原始碼顯示 verb...

Linux Sleep命令暫停Bash指令碼

sleep命令的語法如下 sleep number suffix number可以是正整數或浮點數。suffix可以是下列之一 s 秒 預設 m 分鐘 h 小時 d 天 當沒有使用suffix時,預設為秒。當指定兩個或多個引數時,總時間量等於它們的值之和。下面是幾個簡單的例子,演示如何使用sleep...

bash中的set指令使用說明

先簡單看下set指令常見使用,如下 set o errexit 等價與set e 比較好理解,遇到指令執行後返回非0 就返回終止 set o nounset 等價於set u set o xtrace 等價於set x set o pipefail 適用於管道命令 分析下 管道命令中的最後乙個子命令...