평가 세트("$params") 대신 bash 배열을 사용할 수 있습니까?

평가 세트("$params") 대신 bash 배열을 사용할 수 있습니까?

살펴보고 있어요optparse 라이브러리옵션 구문 분석 의 경우 bash특히 생성된 코드의 다음 지점을 참조하세요.

params=""
while [ $# -ne 0 ]; do
  param="$1"
  shift

  case "$param" in

    --my-long-flag)
      params="$params -m";;
    --another-flag)
      params="$params -a";;
    "-?"|--help)
      usage
      exit 0;;
    *)
      if [[ "$param" == --* ]]; then
        echo -e "Unrecognized long option: $param"
        usage
        exit 1
      fi
      params="$params \"$param\"";;  ##### THIS LINE
  esac
done

eval set -- "$params"  ##### AND THIS LINE

# then a typical while getopts loop

여기에 사용하는 진짜 이유가 있나요 eval? 입력eval ~인 것 같다적절한 소독을 실시합니다. 그러나 다음을 사용하는 것도 똑같이 효과적이지 않을까요?

params=()
# ...
    --my-long-flag)
      params+=("-m");;
    --another-flag)
      params+=("-a");;
# ...
      params+=("$param");;
# ...
set -- "${params[@]}"

나에게는 이것이 더 깨끗해 보인다.

실제로 배열에서 직접 (또는 ? params를 사용하지 않고도 ) 대신 을 사용하여 옵션을 구문 분석할 수 있습니까?setwhile getopts "ma" option "${params[@]}"; dowhile getopts "ma" option; do

답변1

문제는 "~해야 한다평가 세트 대신 bash 배열 사용 - "$params"? ",정답은예!.

스크립트에서 eval에 대한 입력은 분명히 다음과 같습니다.아니요제대로 소독하세요. 노력하다

    yourscript '`xterm`'

백틱이 작은따옴표로 올바르게 묶여 있어도 xterm이 시작되는 것을 볼 수 있습니다. (비교

    echo '`xterm`'

xterm이 시작되지 않습니다. )

버그를 보존하면서 수정하는 것은 eval매우 어렵습니다. 줄을 바꿔도

    params="$params \"$param\"";;

도착하다

    params="$params '$param'";;

아무 소용이 없습니다: 지금

    yourscript '`xterm`'

xterm은 더 이상 시작되지 않지만

    yourscript \'' `xterm` '\'

아직.

답변2

당신은하지 않습니다필요여기에서 배열을 사용하십시오 bash(그러나 기분이 더 좋다면 사용하십시오).

수행 방법은 다음과 같습니다 /bin/sh.

#!/bin/sh

for arg do
    shift

    case "$arg" in
        --my-long-flag)
            set -- "$@" -m ;;
        --another-flag)
            set -- "$@" -a ;;
        "-?"|--help)
            usage
            exit 0 ;;
        --*)
            printf 'Unrecognised long option: %s\n' "$arg" >$2
            usage
            exit 1 ;;
        *)
            set -- "$@" "$arg"
    esac
done

이는 bash다른 변수를 도입할 필요가 없기 때문에 배열 솔루션(개인 의견)보다 깨끗합니다. 또한 각 명령줄 인수를 다음과 같이 유지하므로 표시된 자동 생성 코드보다 낫습니다.별도의 프로젝트존재하다 "$@". 이는 사용자가 따옴표로 묶인 공백 문자가 포함된 매개변수를 전달할 수 있기 때문에 좋습니다(자동 생성된 코드는 이를 수행하지 않음).


스타일 설명:

  • 위의 루프는 나중에 반복할 수 있도록 긴 옵션을 짧은 옵션으로 변환해야 합니다 getopts. 그래서 실제로 작업이 중단됩니다.성능-?및 와 같은 일부 옵션 --help. IMHO는 -h(또는 적절한 짧은 옵션) 로 번역되어야 합니다 .

  • 긴 옵션도 번역할 수 있습니다옵션을 받아들여서는 안되는 지점을 초과했습니다.. 호출 스크립트는 다음과 같습니다.

    ./script.sh --my-long-flag -- -?
    

    ~해야 한다("옵션은 여기서 끝납니다"라는 뜻)은 -?옵션으로 해석되지 않기 때문입니다. --비슷하게,

    ./script.sh filename --my-long-flag
    

    ~해야 한다--my-long-option옵션 구문 분석은 첫 번째 비옵션에서 중지되어야 하므로 옵션으로 해석되지 않습니다 .

위의 사항을 고려한 변형은 다음과 같습니다.

#!/bin/sh

parse=YES

for arg do
    shift

    if [ "$parse" = YES ]; then
       case "$arg" in
            --my-long-flag)
                set -- "$@" -m ;;
            --another-flag)
                set -- "$@" -a ;;
            --help)
                set -- "$@" -h ;;
            --)
                parse=NO
                set -- "$@" -- ;;
            --*)
                printf 'Unrecognised long option: %s\n' "$arg" >$2
                usage
                exit 1 ;;
            *)
                parse=NO
                set -- "$@" "$arg"
        esac
     else
        set -- "$@" "$arg"
     fi

done

이것은 무엇을 위한 것인가?아니요긴 옵션 허용분리--option hello( hello옵션이 아닌 것으로 처리되어 옵션 구문 분석이 종료됩니다) 와 같은 옵션 인수입니다 . --option=hello그러나 몇 가지 추가 수정을 통해 이와 같은 작업을 쉽게 처리할 수 있습니다.

관련 정보