天天看點

shell set指令使用詳解

文章目錄

  • ​​1. set​​
  • ​​2. set -u​​
  • ​​3. set -x​​
  • ​​4. bash 的錯誤處理​​
  • ​​5. set -e​​
  • ​​6. set -o pipefail​​

1. set

會顯示所有的環境變量和 Shell 函數

$ cat script.sh
set 
a=1
b=2
c=3
echo $a
echo $b
echo $c
echo $d      
$ script.sh
 bash script.sh 
BASH=/bin/bash
BASHOPTS=cmdhist:complete_fullquote:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=([0]="0")
BASH_SOURCE=([0]="script.sh")
BASH_VERSINFO=([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
BASH_VERSION='4.3.48(1)-release'      

2. set -u

遇到不存在的變量就會報錯,并停止執行,或者​

​-o nounset​

$ cat script.sh
set -u #-o nounset
a=1
b=2
c=3
echo $a
echo $b
echo $c
echo $d      
$ bash script.sh
1
2
3
script.sh: line 9: d: unbound variable      

3. set -x

用來在運作結果之前,先輸出執行的那一行指令,或者​

​set -o xtrace​

$ cat script.sh 

set -x #set -o xtrace
a=1
b=2
c=3
echo $a
echo $b
echo $c
echo $d      

執行結果:

$ bash script.sh
+ a=1
+ b=2
+ c=3
+ echo 1
1
+ echo 2
2
+ echo 3
3
+ echo      

4. bash 的錯誤處理

#!/usr/bin/env bash

foo
echo bar      

上面腳本中,foo是一個不存在的指令,執行時會報錯。但是,Bash 會忽略這個錯誤,繼續往下執行。

$ bash script.sh
script.sh:行3: foo: 未找到指令
bar      

可以看到,Bash 隻是顯示有錯誤,并沒有終止執行。

這種行為很不利于腳本安全和除錯。實際開發中,如果某個指令失敗,往往需要腳本停止執行,防止錯誤累積。這時,一般采用下面的寫法。

command || exit 1      

上面的寫法表示隻要command有非零傳回值,腳本就會停止執行。

如果停止執行之前需要完成多個操作,就要采用下面三種寫法。

# 寫法一
command || { echo "command failed"; exit 1; }

# 寫法二
if ! command; then echo "command failed"; exit 1; fi

# 寫法三
command
if [ "$?" -ne 0 ]; then echo "command failed"; exit 1; fi      

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

command1 && command2      

5. set -e

set -e從根本上解決了這個問題,它使得腳本隻要發生錯誤,就終止執行。或者​

​set -o errexit​

#!/usr/bin/env bash
set -e

foo
echo bar      

執行結果如下。

$ bash script.sh
script.sh:行4: foo: 未找到指令      

可以看到,第4行執行失敗以後,腳本就終止執行了。

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

set +e
command1
command2
set -e      

上面代碼中,set +e表示關閉-e選項,set -e表示重新打開-e選項。

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

#!/bin/bash
set -e

foo || true
echo bar      

6. set -o pipefail

set -e有一個例外情況,就是不适用于管道指令。

所謂管道指令,就是多個子指令通過管道運算符(|)組合成為一個大的指令。Bash 會把最後一個子指令的傳回值,作為整個指令的傳回值。也就是說,隻要最後一個子指令不失敗,管道指令總是會執行成功,是以它後面指令依然會執行,set -e就失效了。

請看下面這個例子。

#!/usr/bin/env bash
set -e

foo | echo a
echo bar      

執行結果如下。

$ bash script.sh
a
script.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
a
script.sh:行4: foo: 未找到指令      

繼續閱讀