순서가 없으면 bash 스크립트에서 선택적 인수를 구문 분석하는 방법은 무엇입니까?


13

다음 프로그램의 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

그러나 $ 4가 주어 지지만 $ 3가 아니라면?


getopts당신이 원하는 것입니다. 그렇지 않으면 switch 문과 함께 루프를 사용하여 옵션 여부에 관계없이 각 플래그를 감지 할 수 있습니다.
오리온


@orion으로 getopts각 인수 조합을 지정해야합니까? 3 & 4, 3 & 5, 3 & 4 & 5 등?
ShanZhengYang 2016

아니오, 당신은 그것들을 얻는다면 그것들을 설정합니다. 그렇지 않으면 그것을 발견하지 못했다고보고합니다. 그래서 기본적으로 당신은 어떤 순서로든 각각의 옵션을 "얻고"어떤 순서로든 지정합니다. 그러나 bash 맨 페이지를 읽으면 모든 것이 있습니다.
오리온

@ orion 죄송 합니다만, 아직 이해가되지 않습니다 getopts. :하자 내가 모든 인수를 사용하여 스크립트를 실행하는 사용자를 강제로 말 run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSE과 같은 프로그램을 실행합니다 program --flag1 VAL --flag2 VAL. 실행 run_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE하면 프로그램이 다음과 같이 실행됩니다 program --flag1 VAL --flag2 VAL --optflag2 10. 어떻게 그런 행동을 할 수 getopts있습니까?
ShanZhengYang

답변:


25

이 문서에서는 쇼 두 가지 방법 - shiftgetopts(과에 나와있는 두 가지 방법의 장점과 단점).

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) 옵션을 원하는지 등입니다.


나는 보통 이렇게 while (( $# ))대신 while :;종종에서 오류로 종료 *하는 경우
Jasen

이것은 제목에는 대답하지만 질문에는 대답하지 않습니다.
Jasen

@Jasen 나는 지난 밤에 이것을 보았고 내 인생을 볼 수 없었습니다. 오늘 아침에 훨씬 더 명확 해졌습니다 (이제 오리온의 대답도 보았습니다). 오늘이 답변을 나중에 삭제하겠습니다 (먼저 의견을 확인하고 싶었으며 가장 쉬운 방법 인 것 같습니다).
John N

문제 없습니다. 여전히 좋은 대답입니다. 질문 만 피하십시오.
Jasen

1
NB : set -o nounset첫 번째 솔루션의 경우 매개 변수가 제공되지 않으면 오류가 발생합니다. 수정 :case ${1:-} in
Raphael

3

배열을 사용하십시오.

#!/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[@]}"

공백이 포함 된 인수를 올바르게 처리합니다.

[편집] 나는 대략 eqivalent 구문을 사용하고 args=( "${args[@]}" --optflag1 "$3" )있었지만 G-Man은 더 나은 방법을 제안했습니다.


1
을 말하면이 작업을 간소화 할 수 있습니다 args+=( --optflag1 "$3" ). 참조 작업 에 대한 나의 대답 , bash / POSIX shells에서 변수를 인용하지 못하는 보안 함의 를 볼 수 있습니다 .
G-Man, 'Reinstate

@ G-Man 감사합니다. 설명서에서 [@]문제를 해결하기에 충분한 도구가 있다는 것을 이해하지 못했습니다 .
Jasen

1

쉘 스크립트에서 인수는 "$ 1", "$ 2", "$ 3"등입니다. 인수의 수는 $ #입니다.
스크립트가 옵션을 인식하지 못하면 옵션 감지를 생략하고 모든 인수를 피연산자로 취급 할 수 있습니다.
옵션을 인식하려면 getopts 내장을 사용하십시오.


0

귀하의 경우 입력 옵션 위치입니다 (당신은 그들이에있는 곳을 알고), 및 플래그로 지정하지, 다음 당신이 원하는 것은 단지 명령 줄을 구축하는 것입니다. 명령 인수를 모두 준비하십시오.

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를 사용하는 것은 약간 비표준적이고 꽤 길다. 일반적으로 -빈 값을 알리기 위해 단일 문자 ( )를 사용하거나 ""매개 변수의 유효한 값이 아닌 경우 빈 문자열을 전달합니다 . 빈 문자열은 테스트를 더 짧게 만듭니다 if [ -n "$3" ].
  • 옵션 플래그가 하나만 있거나 종속되어 있으므로 OPTFLAG2를 가질 수 없지만 OPTFLAG1을 가질 수없는 경우 설정하지 않으려는 플래그를 건너 뛸 수 있습니다. ""위에서 제안한 것처럼 빈 매개 변수 를 사용 하는 경우 어쨌든 모든 후미를 건너 뛸 수 있습니다.

이 방법은 옵션이 Makefile의 컴파일러에 전달되는 방식과 거의 같습니다.

그리고 다시-입력에 공백이 포함되어 있으면 추악합니다.


아니오, 쉘이 매개 변수를 단어로 나누기를 원하지 않습니다. 타당한 이유가없는 한 항상 쉘 변수에 대한 모든 참조를 인용해야하며 수행중인 작업을 확실히 알고 있어야합니다. 익숙하지 않은 경우 bash / POSIX 셸에서 변수를 인용하지 못하면 보안에 미치는 영향을 참조 하고이 답변을 정확하게 아래로 스크롤하여 내 대답으로 스크롤하십시오 ( Jasen이 사용 하는 것과 동일한 기술 사용 ).
G-남자 '는 분석 재개 모니카'말한다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.