Linux
從 bash 中的函式中獲取和設置腳本參數
語境:
我有一個舊的 bash 腳本,其中有一大段解析它的參數。現在我需要呼叫這個部分兩次,所以我打算把它移到一個函式中以避免程式碼重複。
問題:
在該部分中
set --
,shift
和$@
被使用,這意味著它們將不再適用於腳本,而是適用於函式,這是錯誤的。問題:
從函式內部,有沒有辦法獲取和設置腳本參數?
方案:
像這樣的東西:
#!/bin/bash # > 5000 lines process_arg() { # about 650 lines # set -- # $@ $* $1 ... # shift <n> } while (( $# > 0 )); do case $1 in <cond>) <some code here> process_arg <some more code here> <other conditions and code here> *) <some different code here> process_arg <some different more code here> esac shift 1 done
免責聲明:
從上面的討論中,我實現了一個解決方案。到目前為止,這不是我夢寐以求的,因為冗長 $ {args_array[1]}, compared to $ 1. 降低原始碼的可讀性。因此,仍然歡迎改進或更好的解決方案。
來源:
經測試,是這樣的:
#!/bin/bash ######################### # DEBUG ######################### # set -x PS4='${xchars:-+} ${BASH_SOURCE}:${LINENO} (${FUNCNAME[@]}) + ' # full stack ######################### # INITIAL ARGS FOR TEST ######################### set -- a b c d e f g h ######################### # UTILITIES ######################### args_array=( "$@" ) # script args here args_shift() # Usage readability OK, replaces shift <n> { typeset n=${1:-1} echo "args_shift $1 in ${FUNCNAME[1]} -- ${args_array[@]}" args_array=( "${args_array[@]:$n}" ) # ${1:-1} unsupported in this context echo "args_shift $1 in ${FUNCNAME[1]} ++ ${args_array[@]}" } args_set() # Usage readability OK, replaces set -- <args> { echo "args_set $@ in ${FUNCNAME[1]} -- ${args_array[@]}" args_array=( "$@" ) # function args here echo "args_set $@ in ${FUNCNAME[1]} ++ ${args_array[@]}" } # Usage # search/replace OK, and good readability afterward # shift <n> ---> args_shift <n> # set -- <args> ---> args_set <args> # search/replace OK, but bad readability afterward, and refactoring-- # $@ ---> ${args_array[@]} # $# ---> ${#args_array[@]} # $1 ---> ${args_array[0]} !!! 1 -> 0 # $2 ---> ${args_array[1]} !!! 2 -> 1 # etc ######################### # TEST ######################### f() { args_shift } g() { args_set A B C D } # main echo "main -- ${args_array[@]}" f args_shift 2 f g args_shift f echo "main ++ ${args_array[@]}"
輸出:
main -- a b c d e f g h args_shift in f -- a b c d e f g h args_shift in f ++ b c d e f g h args_shift 2 in main -- b c d e f g h args_shift 2 in main ++ d e f g h args_shift in f -- d e f g h args_shift in f ++ e f g h args_set A B C D in g -- e f g h args_set A B C D in g ++ A B C D args_shift in main -- A B C D args_shift in main ++ B C D args_shift in f -- B C D args_shift in f ++ C D main ++ C D
評論:
- 有效但不是最易讀的解決方案,重構也不是那麼輕鬆,因為有幾種使用形式需要考慮: $ 1, more or less $ {1$$ :/ $$$$ ^} $$} 或 ${!1$$ :/ $$$$ ^} $$} 等,同時避免那些在函式,awk,perl 等。
- 對於某些人來說,由於變數名在 bash 中區分大小寫,而且我認為或多或少很少使用,因此 on 可以使用 A 或 _A 而不是 args_array 但是,根據我的口味, $ {A[1]} or so is even less readable in a long source than $ {args_array$$ 1 $$}.
我的情況:
至少有 616 次事件需要小心處理(有些在函式、awk 或 perl 腳本等中)
for s in shift 'set --' '$@' '${@' '$*' '${*' '$1' '${1' '$2' '${2' '$3' '${3' '$4' '${4' '$5' '${5'; do printf '%-10s: %d\n' "$s " "$(fgrep $s <script>|wc -l)" done # |awk '{sum+=$NF};END{print sum}' shift : 44 set -- : 189 $@ : 39 ${@ : 2 $* : 7 ${* : 0 $1 : 182 ${1 : 79 $2 : 48 ${2 : 3 $3 : 15 ${3 : 0 $4 : 8 ${4 : 0 $5 : 0 ${5 : 0