[unix] 순서가 없으면 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

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



답변

이 문서에서는 쇼 두 가지 방법 – 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) 옵션을 원하는지 등입니다.


답변

배열을 사용하십시오.

#!/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”, “$ 2”, “$ 3″등입니다. 인수의 수는 $ #입니다.
스크립트가 옵션을 인식하지 못하면 옵션 감지를 생략하고 모든 인수를 피연산자로 취급 할 수 있습니다.
옵션을 인식하려면 getopts 내장을 사용하십시오.


답변

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

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의 컴파일러에 전달되는 방식과 거의 같습니다.

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


답변