문맥:
인수를 구문 분석하는 큰 섹션이 있는 오래된 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
답변1
부인 성명:
위의 논의를 바탕으로 솔루션을 구현했습니다. ${args_array[1]}가 $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, 다소 ${1[:/][^}]} 또는 ${!1[:/][^}]} 등을 사용하고 함수, awk, Perl 등을 사용하지 마세요.
- 어떤 사람들에게는 변수 이름이 bash에서 대소 문자를 구분하고 거의 사용되지 않는다고 생각하기 때문에 args_array 대신 A 또는 _A를 사용할 수 있지만 내 취향에 따라 ${A[1] } 소스 코드는 다음보다 읽기가 훨씬 어렵습니다. ${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