Bash의 함수 내에서 스크립트 매개변수 가져오기 및 설정

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

답변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[:/][^}]} 또는 ${!1[:/][^}]} 등을 사용하고 함수, awk, Perl 등을 사용하지 마세요.
  2. 어떤 사람들에게는 변수 이름이 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

관련 정보