순서가 지정되지 않은 경우 bash 스크립트에서 선택적 매개변수를 구문 분석하는 방법은 무엇입니까?

순서가 지정되지 않은 경우 bash 스크립트에서 선택적 매개변수를 구문 분석하는 방법은 무엇입니까?

다음 프로그램에 대한 bash 스크립트를 작성할 때 선택적 매개변수/플래그를 포함하는 방법이 혼란스럽습니다.

이 프로그램에는 두 가지 매개변수가 필요합니다.

run_program --flag1 <value> --flag2 <value>

그러나 다음과 같은 몇 가지 선택적 플래그가 있습니다.

run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value> 

사용자 매개변수를 허용하도록 bash 스크립트를 실행하고 싶습니다. 사용자가 두 개의 매개변수만 순서대로 입력하면 다음과 같습니다.

#!/bin/sh

run_program --flag1 $1 --flag2 $2

하지만 선택적 매개변수가 포함되면 어떻게 될까요? 내 생각엔 그럴 것 같아

if [ --optflag1 "$3" ]; then
    run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi

하지만 3달러 대신 4달러를 받았다면 어떨까요?

답변1

이 기사두 가지 다른 접근 방식 shift이 표시됩니다 getopts(그리고 두 접근 방식의 장점과 단점에 대해 논의합니다).

shift스크립트를 사용하여 보고 $1, 수행할 작업을 결정한 다음 실행 shift, 이동 $2, $1이동 $3$2을 수행합니다.

예를 들어:

while :; do
    case $1 in
        -a|--flag1) flag1="SET"            
        ;;
        -b|--flag2) flag2="SET"            
        ;;
        -c|--optflag1) optflag1="SET"            
        ;;
        -d|--optflag2) optflag2="SET"            
        ;;
        -e|--optflag3) optflag3="SET"            
        ;;
        *) break
    esac
    shift
done

getopts표현식 에서 (짧은) 옵션을 정의 할 수 있습니다 while.

while getopts abcde opt; do
    case $opt in
        a) flag1="SET"
        ;;
        b) flag2="SET"
        ;;
        c) optflag1="SET"
        ;;
        d) optflag2="SET"
        ;;
        e) optflag3="SET"
        ;;
    esac
done

분명히 이것은 단지 코드 조각일 뿐이므로 유효성 검사를 생략했습니다. 필수 매개변수인 flag1 및 flag2가 설정되어 있는지 확인하는 것 등입니다.

어떤 방법을 사용하는지는 선호도에 따라 달라집니다. 즉, 스크립트의 이식성을 원하는지, 짧은 옵션(POSIX)만 허용하는지 또는 긴 옵션(GNU)을 원하는지 등입니다.

답변2

배열을 사용하세요.

#!/bin/bash

args=( --flag1 "$1" --flag2 "$2" )
[  "x$3" = xFALSE ] ||  args+=( --optflag1 "$3" )
[  "x$4" = xFALSE ] ||  args+=( --optflag2 "$4" )
[  "x$5" = xFALSE ] ||  args+=( --optflag3 "$5" )
[  "x$6" = xFALSE ] ||  args+=( --optflag4 "$6" )
[  "x$7" = xFALSE ] ||  args+=( --optflag5 "$7" )

program_name "${args[@]}"

그러면 공백이 포함된 매개변수가 올바르게 처리됩니다.

[편집] 나는 거의 동일한 구문을 사용하고 있지만 args=( "${args[@]}" --optflag1 "$3" )G-Man이 더 나은 방법을 생각해냈습니다.

답변3

쉘 스크립트에서 매개변수는 "$1", "$2", "$3" 등입니다. 매개변수 개수는 $#입니다.
스크립트가 옵션을 인식하지 못하는 경우 옵션 감지를 무시하고 모든 인수를 피연산자로 처리할 수 있습니다.
옵션을 식별하려면 내장된 getopts를 사용하세요.

답변4

만약 당신의입력하다옵션은 위치에 따라 다르며(어디에 있는지 알 수 있음) 플래그로 지정되지 않습니다. 그러면 원하는 것은 명령줄을 작성하는 것뿐입니다. 모든 항목에 대한 명령 매개변수를 준비하세요.

FLAG1="--flag1 $1"
FLAG2="--flag2 $2"
OPTFLAG1=""
OPTFLAG2=""
OPTFLAG3=""
if [ xFALSE != x"$3" ]; then
   OPTFLAG1="--optflag1 $3"
fi
if [ xFALSE != x"$4" ]; then
   OPTFLAG2="--optflag2 $4"
fi
#the same for other flags

#now just run the program
runprogram $FLAG1 $FLAG2 $OPTFLAG1 $OPTFLAG2 $OPTFLAG3

인수가 지정되지 않으면 해당 문자열은 비어 있고 아무것도 확장되지 않습니다. 마지막 줄에는 따옴표가 없습니다. 이는 쉘이 인수를 단어로 분할 --flag1하고 $1프로그램에 대한 별도의 인수로 분할하기를 원하기 때문입니다. 물론, 원래 매개변수에 공백이 포함되어 있으면 이것이 잘못됩니다. 이 스크립트를 실행하는 사람이라면 그대로 둘 수 있지만 일반 스크립트인 경우 사용자가 공백이 포함된 항목을 입력하면 예기치 않게 동작할 수 있습니다. 이 문제를 해결하려면 코드를 좀 더 보기 흉하게 만들어야 합니다.

x테스트의 접두사는 []대소문자가 있거나 $3비어 $4있습니다. 이 경우 bash는 구문 오류 [ FALSE != $3 ]로 확장되므로 이를 방지하기 위해 다른 임의의 문자를 사용할 수 있습니다. [ FALSE != ]이는 매우 일반적인 접근 방식이며 많은 스크립트에서 볼 수 있습니다.

확실하게 하기 위해 처음에 OPTFLAG1이들 항목과 나머지 항목을 설정했지만 ( 이전에 설정한 경우) 환경에서 실제로 선언되지 않은 경우 엄격하게 이 작업을 수행할 필요는 없습니다.""

몇 가지 추가 참고 사항:

  • 실제로 runprogram플래그를 사용하여 동일한 방식으로 매개변수를 받을 수 있습니다. 그것이 우리가 John N부르는 것입니다. 이것이 getopts유용한 곳 입니다 .
  • 이 목적으로 FALSE를 사용하는 것은 다소 비표준적이고 시간이 오래 걸립니다. 일반적으로 단일 문자(아마도 -)를 사용하여 null 값을 나타내거나 빈 문자열을 전달합니다(예: ""매개변수에 유효한 값이 아닌 경우). 빈 문자열을 사용하면 테스트가 더 짧아지므로 if [ -n "$3" ].
  • 선택적 플래그가 하나만 있거나 서로 관련되어 OPTFLAG2는 가질 수 없지만 OPTFLAG1은 가질 수 없는 경우 설정하고 싶지 않은 플래그를 건너뛸 수 있습니다. 위에서 제안한 것처럼 null 인수를 사용하는 경우 ""어쨌든 후행 null 인수를 건너뛸 수 있습니다.

이 접근 방식은 Makefile에서 옵션이 컴파일러에 전달되는 방식과 거의 유사합니다.

다시 말하지만, 입력에 공백이 포함되어 있으면 보기 흉해집니다.

관련 정보