2018年11月4日 星期日

bash: SHELL GRAMMAR

bash 基本指令以 control operator 結束,組成成份用 blank 分隔,格式依序如下:
[變數指定...] 指令 [引數...][輸出入導向]
用到的 metacharacter 除了輸出入轉向,就只有 blank。

回傳值是 exit status。如果被 signal n 結束,回傳 128+n 。

基本指令可以組合成 Pipeline 和 Lists。另外還有 Compound Commands、Coprocesses、Function。

Pipelines

pipeline 是一系列用控制運算子「|」或「|&」分隔的一個以上基本指令 (一個也算!?)。
[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]
前一個指令的標準輸出透過 pipe 導到下個指令的標準輸入。如果使用「|&」包含標準錯誤一併導向,相當於「2>&1 |」。


所有指令結束後才回傳最後指令的離開狀態。但如果啟用 pipefail 選項時,回傳最後回傳非 0 指令的狀態。如果 pipeline 前面有 !,邏輯反向離開狀態。

如果前面有保留字 time,結束時回報執行歷經的時間、耗用的使用者及系統時間。加選項 -p 採用 POSIX 輸出格式。如果在 posix 模式,下個 token 以「-」開始,time 不作為保留字。可設定變數 TIMEFORMAT 指定時間訊息的顯示格式。

如果在 posix 模式,time 之後可能跟著換行,此時顯示 shell 和其 children 耗用的全部使用者和系統時間。

pipeline 的每個指令都在獨立的行程 (i.e., subshell) 執行。
一個 pipeline 稱為一個 job。

Lists

list 是一系列用控制運算子 「;」、「&」、「&&」或「||」分隔的一個以上 pipeline,最後可以「;」或「&」結束。<newline> 可取代「;」。

這些 list 運算子前後有特定的執行關係:
  • 「&&」:執行成功 (回傳 0) 才執行後面的指令。
  • 「||」:執行失敗 (回傳非 0) 才執行後面的指令。
  • 「;」或換行:等候執行完成後再執行後面的指令。
  • 「&」:在 subshell 背景執行,不等候完成直接回傳 0,後面指令開始執行。
其中「&&」和「||」有相同 precedence,再來是「;」和「&」有相同 precedence。
List 最後回傳最後指令執行的結果。

Compound Commands

複合指令

(list)

在 subshell 環境執行 list (見 bash COMMAND EXECUTION ENVIRONMENT),結束不影響原本環境變數。

{ list; }

在目前 shell 環境執行 list。需要以 <newline> 或「;」結束,是由於「{」、「 }」只是保留字,不是 metacharacter 能區隔出字,需要有 metacharacter 區隔出字來,且 list 必須有「;」或換行表示最後的指令結束。

((expression))

進行算術運算,結果 0 回傳 1;否則回傳 0。

[[ expression ]]

依據 conditional expression 是 true 回傳 0,否則回傳 1。不進行 Word splitting 和 pathname expansion。進行 tilde expansion、parameter and variable expansion、arithmetic expansion、command  substitution、process  substitution、和 quote removal。Conditional operators such as -f must be unquoted to be recognized as primaries.

當 == (或 =) 或 != 用在 [[ 指令,右邊是 pattern 進行 Pattern Matching,如同啟用選項 extglob。如果啟用選項 nocasematch,比對不分大小寫。pattern 任何部份可以 quoted 來強迫直接字串比對。

另外還有額外 binary operator「=~」使用 extended  regular  expression (regex()),如果  regular  expression syntactically 錯誤回傳 2。Substrings  matched  by parenthesized subexpressions within the regular expression 存在 BASH_REMATCH 陣列,其中 index 0 是整個符合的部份,index n 是第 n 個parenthesized subexpression 符合的部份。

用下列優先權,表示式可以結合:
( expression ):優先進行。
! expression:True if expression is false.
expression1 && expression2:expression1 false 回傳 false,否則看 expression2 是否 true。
expression1 || expression2:expression1 true 回傳 true,否則看 expression2 是否 true。

for name [ [ in [ word ... ] ] ; ] do list ; done

擴展 in 之後的 word 列表產生許多項目,變數 name 依序設成每個項目來執行 list。如果省略 in word,則拿有設的位置參數當作項目。

for (( expr1 ; expr2 ; expr3 )) ; do list ; done

expr1、expr2、和 expr3 都是 arithmetic expression,如有省略則 evaluate 為 1。首先計算 expr1,然後重複計算 expr2 直到為 0。每次 expr2 算出不為 0,執行 list 後計算 expr3。

select name [ in word ] ; do list ; done

擴展 in 之後的 word 列表產生許多項目,在標準錯誤前置順序數字印出。如果省略 in word,則拿有設的位置參數當作項目。然後顯示 PS3 prompt,讀取標準輸入選擇項目設為 name 執行 list。直到讀到 EOF 後結束。讀到其它不合理的值 name 會設為 null。讀到的會存在變數 REPLY。

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

首先擴展 word,然後依序比對每個 pattern,採用 pathname 擴展的比對方式。word 用到的擴展有 tilde expansion、parameter  and  variable  expansion、arithmetic  expansion、command substitution、process substitution、和 quote removal。每個檢查的 pattern 用到的擴展有 tilde expansion、parameter and variable expansion、arithmetic expansion、command substitution、和 process substitution。如果啟用選項 nocasematch,比對不管大小寫。當找到一個符合,執行對應的 list。如果使用 ;; operator,不進行後續比對。如果使用 ;&,持續執行下個 pattern 的 list。使用 ;;& 持續比對剩下的 patten,如果符合執行其 list。比對沒符合回傳 0。

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

執行 if list,回傳 0 則執行 then list,否則依序執行每個 elif  list 如果回傳 0 執行對應的 then list 後結束。都沒有回傳 0,執行 else list。

while list-1; do list-2; done
until list-1; do list-2; done

while:只要 list-1 回傳 0,不斷執行 list-2 。
until:只要 list-1 回傳 0,不斷執行 list-2 。 

Coprocesses

coprocess 是前置保留字 coproc 的 shell 指令,在子 shell 背景執行,並建立雙向 pipe。
coproc [NAME] command [redirections]
建立名為 NAME 的 coprocess,預設名稱是 COPROC。如果 command 是基本指令,不能提供 NAME,否則會被解釋成基本指令的第一個字。當 coprocess 執行時,會建立名為 NAME 的陣列。指令的標準輸出透過 pipe 連結到指定給 NAME[0] 的 file descriptor,指令的標準輸入透過 pipe 連結到指定給 NAME[1] 的 file descriptor。pipe 在任何 redirection 前建立。那些 file descriptor 可用標準 word expansion 作為其它指令的引數或導向。執行 coprocess 的 process ID 可見變數 NAME_PID。內建指令 wait 可用來等候 coprocess 結束。

Shell Function

shell 函數像基本指令一樣呼叫,暫時使用新的一組位置參數來自引數和參數 # 執行 compound command,結束後回復。如下宣告名為 name 的 shell 函數:

[function] name () compound-command [redirection]
function name { compound-command; } [redirection]
有 () 可以不需要保留字 function,沒有 () 需要 { list; }。

在 posix 模式,name 不可以跟 POSIX special builtins 一樣。shell 函數定義的離開狀態是 0,除非有 syntax 錯誤或 name 跟 readonly 函數相同。執行的離開狀態是裡面最後執行指令的離開狀態。

shell function stores  a  series  of commands for later execution.
Functions are executed
       in the context of the current shell;  no  new  process  is  created  to
       interpret  them  (contrast  this with the execution of a shell script).

特殊參數 0 不變,變數 FUNCTNAME 的 first  element 設為函數名稱。

其它執行環境不變,除了
  • DEBUG 和 RETURN traps (見 bash 內建指令 trap),除非函數有給 trace 屬性 (見內建指令 declare) 或透過內建指令 set 啟用 shell 選項 -o functrace
  • ERR trap,除非啟用 shell 選項 -o errtrace。
變數跟 caller 共享,函數 local 變數可以用內建指令 local 宣告。

函數可以 recursive 執行。變數 FUNCNEST 如果設為大於 0 的值,限制函數最大 nesting level,執行超過的話造成整個 command abort。

函數內執行內建指令 return,結束函數,RETURN  trap 的指令會執行。

函數名稱和定義可用有 -f 選項的內建指令 declare 或  typeset 列出。-F 選項只列出函數名稱。函數可用內建指令 export -f 匯出給子 shell 使用。內建指令 unset -f 可刪除函數。註:相同名稱的函數和變數會造成傳遞的環境變數 multiple identically-named  entries 而可能造成問題。

參考來源

bash mag-page 的 SHELL GRAMMAR 和 FUNCTIONS 節

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...