[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가 아니라면?
답변
이 문서에서는 쇼 두 가지 방법 – 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) 옵션을 원하는지 등입니다.
답변
배열을 사용하십시오.
#!/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의 컴파일러에 전달되는 방식과 거의 같습니다.
그리고 다시-입력에 공백이 포함되어 있으면 추악합니다.