다양한 옵션을 허용하는 쉘 스크립트가 있는데, 일부는 매개변수가 있고 일부는 매개변수가 없고 일부는 짧고 일부는 길다. 이러한 옵션 중 일부를 자체적으로 처리하고 나머지는 어떻게 관리해야 할지 모르는 다른 프로그램에 전달해야 합니다. getopts
알 수 없는 매개변수를 저장하는 것과 유사한 것을 얻을 수 있습니까 ?
program
예를 들어 내 스크립트가 호출되어 인수를 받아들여야 한다고 가정해 보겠습니다.
-n
하나의 매개변수로,--verbose
논쟁의 여지가 없으며-s
논쟁의 여지가 없습니다.
모든 옵션과 해당 인수를 구문 분석하고 인쇄한 다음 echo rest:
남은 항목을 호출합니다. 다음 출력을 관찰해야 합니다.
> program -sin42 --long --verbose
-s
-n with argument 42
--verbose
rest: -i --long
> program -n --short
-n with argument --short
> program -n
error: -n without argument
쉘 스크립트에서 이와 같은 작업을 수행할 수 있습니까?
답변1
쉘에서 널리 사용되는 것은 물론이고 이를 수행하는 표준 방법도 없다고 생각합니다(즉, 처음부터 구현하는 것이 부족함).
매우 강력한 내장 기능을 ksh
지원 하지만 . getopts
이것(및 다소 까다로운 요구 사항)을 기반으로 ksh
다음 코드 조각을 사용하여 가능한 기본 솔루션의 개요를 설명했습니다.
while getopts ":[-][[n]:][99:verbose][s]" opt
do case $opt in
(n) n_arg=$OPTARG ;;
(99) verbose=1 ;;
(s) s=1 ;;
(*) arg_rest+=( "${@:OPTIND-1:1}" ) ;;
esac
done
shift OPTIND-1
printf "main opt(%s)=%s\n" "-n" "$n_arg"
printf "main opt(%s)=%s\n" "--verbose" "$verbose"
printf "main opt(%s)=%s\n" "-s" "$s"
function delegate
{
while getopts ":[-][i][98:long]" opt
do case $opt in
(i) int=1 ;;
(98) long=1 ;;
esac
done
shift OPTIND-1
printf "func opt(%s)=%s\n" "-i" "$int"
printf "func opt(%s)=%s\n" "--long" "$long"
}
printf "Delegate: '%s'\n" "${arg_rest[@]}"
delegate "${arg_rest[@]}"
프로그램은 먼저 모든 옵션을 구문 분석하고 필요에 따라 내부 변수를 설정한 다음 알 수 없는 옵션을 배열에 저장합니다. 그러면 printf
설정을 제어할 수 있는 몇 가지 옵션이 표시됩니다 . 그런 다음 나머지 옵션이 위임될 함수 정의가 제공되며 해당 함수는 명령으로 대체될 수도 있습니다. 마지막으로 나머지 매개변수를 사용하여 함수(또는 다른 명령)를 호출합니다.
ksh
(함수에 대한 설명은 세션 getopts
에서 호출하세요 .)ksh
getopts --man
이 프로그램을 실행하면 다음과 같은 출력이 생성됩니다.
$ ksh ./getopts_script -s -n 23 --verbose -i --long
main opt(-n)=23
main opt(--verbose)=1
main opt(-s)=1
Delegate: '-i'
Delegate: '--long'
func opt(-i)=1
func opt(--long)=1
긴 옵션을 지원하는 getopts 함수의 셸 구현은 다음을 참조하세요.https://github.com/stephane-chazelas/misc-scripts/blob/master/getopts_long.sh
답변2
getopt
이미 알려진 옵션을 선주문하는 것은 쉽습니다 . 안타깝게도 알 수 없는 모든 매개변수를 거부하고 구문 분석을 즉시 중지합니다.
그러나 긴 옵션이 지나치게 복잡하지 않은 한 bash를 속여서 getopts
이 작업을 수행할 수 있습니다 . 어떤 영감은 다음에서 비롯됩니다.mkaurball
. 출처 아래에 참고사항이 포함되어 있습니다.
#!/bin/bash
while [ $OPTIND -le $# ]
do
if getopts ":sn:-:" argument
then
case $argument in
s) echo "-$argument" ;;
n) echo "-$argument with argument $OPTARG" ;;
\?) pass+=("-$OPTARG") ;;
-) lastarg=$((OPTIND - 1))
case "${!lastarg}" in
--verbose) echo "--verbose" ;;
--*) pass+=("--$OPTARG") ;;
*) echo "invalid argument: -"
exit 1 ;;
esac ;;
:) echo "$OPTARG without argument"
exit 1 ;;
esac
else
pass+=("${!OPTIND}")
let OPTIND++
fi
done
echo pass: "${pass[@]}"
- 일반적으로
getopts
s는 조건으로 사용되지 않습니다while
. 이로 인해 위치 인수(즉, 옵션도 인수도 아닌 인수)를 만나자마자 루프가 중지됩니다. 대신 이러한 사례는 매개변수가 수집되는 배열에 추가됩니다pass
. - 매개변수 사양에는 긴 옵션이 매개변수가 있는 짧은 옵션으로 처리되도록 하는
:-
가 포함됩니다 . 짧은 옵션 복합어(예를 들어)의 중간에 대시를 혼합하면 부주의하게 사용하면 이 문제가 발생할 수 있으므로 실제 인수가 실제로 두 개의 대시로 시작하는지 확인하는 것이 좋습니다. 따라서 래핑된 프로그램이 옵션을 옵션으로 처리하려는 경우 이 메서드는 실패합니다.getopts
--long
-
-long
-s-n
-short-with-dashes
- 본질적으로
getopts
이중 대시도 삼켜집니다. 이는 바람직할 수도 있지만[ "${!OPTIND}" != '--' ] &&
앞에 삽입하여 피할 수도 있습니다.getopts
- 래퍼는 중첩된 매개변수 내에 있어야 하기 때문에 긴 매개변수를 구문 분석하는 데 약간의 어려움이 있을 수 있습니다
case
.