跳轉到內容

Bash Shell 指令碼/Shell 函式

來自華夏公益教科書,自由的教科書

Shell 函式是一種特殊型別的變數,本質上是指令碼中的指令碼。此功能允許我們將一系列命令分組到單個命名命令中,這在需要在指令碼中的多個位置執行一系列命令時特別有用。Shell 函式甚至可以僅包含單個命令;如果命令特別複雜,或者其重要性不會立即對讀者顯而易見,這可能很有用。(也就是說,Shell 函式可以服務於兩個目的:它們可以節省輸入,並且可以透過建立直觀的命名命令來使程式碼更易讀。)請考慮以下指令碼

#!/bin/bash
# Usage:     get_password VARNAME
# Asks the user for a password; saves it as $VARNAME.
# Returns a non-zero exit status if standard input is not a terminal, or if the
# "read" command returns a non-zero exit status.
get_password() {
  if [[ -t 0 ]] ; then
    read -r -p 'Password:' -s "$1" && echo
  else
    return 1
  fi
}

get_password PASSWORD && echo "$PASSWORD"

以上指令碼建立了一個名為get_password的 Shell 函式,它要求使用者輸入密碼並將結果儲存在指定的變數中。然後它執行get_password PASSWORD 將密碼儲存為$PASSWORD;最後,如果對get_password的呼叫成功(由其退出狀態決定),則檢索到的密碼將被列印到標準輸出(這顯然不是實際用途;這裡的目標只是為了演示get_password的行為)。

函式get_password沒有做任何在沒有 Shell 函式的情況下做不到的事情,但結果更易讀。該函式呼叫內建命令read(它讀取一行使用者輸入並將其儲存在一個或多個變數中)以及大多數 Bash 程式設計師不熟悉的一些選項。(-r 選項停用反斜槓字元的特殊含義;-p 選項導致在行首顯示指定的提示,在本例中為Password:-s 選項阻止使用者鍵入的密碼顯示。由於-s 選項還會阻止使用者的新行顯示,因此echo 命令提供了一個新行。)此外,該函式使用條件表示式-t 0來確保指令碼的輸入來自終端(控制檯),而不是來自檔案或另一個不知道正在請求密碼的程式。(這個最後的特性是可爭議的;根據指令碼的總體功能,最好接受來自標準輸入的密碼,無論其來源如何,假設源是考慮到指令碼而設計的。)總的來說,給一系列命令命名——get_password——使程式設計師更容易瞭解它所做的事情。

在 Shell 函式中,位置引數($1$2 等等,以及$@$*$#)是指呼叫函式時傳遞的引數,而不是包含該函式的指令碼的引數。如果需要後者,則需要使用"$@" 顯式地將它們傳遞給函式。(即使那樣,shiftset 也會隻影響函式中的位置引數,而不是呼叫者的位置引數。)

函式呼叫會返回退出狀態,就像指令碼(或幾乎任何命令)一樣。要顯式指定退出狀態,請使用return 命令,它會終止函式呼叫並返回指定的退出狀態。(exit 命令不能用於此目的,因為它會終止整個指令碼,就像在函式外部呼叫它一樣。)如果未指定退出狀態,無論是由於未向return 命令提供任何引數,還是由於在未執行return 命令的情況下到達函式的末尾,則函式將返回上次執行命令的退出狀態。

順便說一句,function( ) 可以從函式宣告中省略,但必須至少存在一個。許多程式設計師編寫get_password(),而不是function get_password ( )。類似地,{ … } 符號並不是嚴格要求的,也不是特定於函式的;它只是將一系列命令組合成單個複合命令的符號。函式的主體必須是複合命令,例如{ … } 塊或if 語句;{ … } 是傳統的選擇,即使它只包含一個複合命令,並且理論上可以省略。

華夏公益教科書