![긴 옵션을 처리하려면 getopts를 사용하세요.](https://linux55.com/image/197737/%EA%B8%B4%20%EC%98%B5%EC%85%98%EC%9D%84%20%EC%B2%98%EB%A6%AC%ED%95%98%EB%A0%A4%EB%A9%B4%20getopts%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%84%B8%EC%9A%94..png)
옵션을 구문 분석 중이지만 getopts
긴 옵션도 처리하고 싶습니다.
print-args ()
{
title="$1" ; shift
printf "\n%s\n" "${title}: \$@:"
for arg in "$@"; do
(( i = i + 1 ))
printf "%s |%s|\n" "${i}." "$arg"
done
}
getopts_test ()
{
aggr=()
for arg in "$@"; do
case $arg in
("--colour"|"--color") aggr+=( "-c" ) ;;
("--colour="*|"--color="*) aggr+=( "-c" "${arg#*=}" ) ;;
(*) aggr+=( "$arg" ) ;;
esac
done
print-args "print" "$@"
eval set -- "${aggr[@]}"
print-args "eval" "$@"
set -- "${aggr[@]}"
print-args "set" "$@"
local OPTIND OPTARG
local shortopts="C:"
while getopts "$shortopts" arg; do
case $arg in
("c") context="$OPTARG" ;;
(*) break ;;
esac
done
shift $(( OPTIND - 1 ))
}
그런데 사용법이 맞는지 알고 싶습니다 set -- "${aggr[@]}"
.
아니면 다음 ( 을 사용하여 eval
)이 더 적합합니까?
eval set -- "${aggr[@]}"
아래와 같이 테스트를 진행했습니다. 문자열 "Gunga Din"은 eval을 사용할 때 분할되지만, eval을 사용할 때는 set -- "${aggr[@]}"
단일 문자열로 올바르게 구문 분석됩니다 .
getopts_test -f -g 130 --colour="170 20" "Gunga Din"
print: $@:
1. |-f|
2. |-g|
3. |130|
4. |--colour=170 20|
5. |Gunga Din|
eval: $@:
1. |-f|
2. |-g|
3. |130|
4. |-c|
5. |170|
6. |20|
7. |Gunga|
8. |Din|
set: $@:
1. |-f|
2. |-g|
3. |130|
4. |-c|
5. |170 20|
6. |Gunga Din|
그런 다음 비 GNU를 사용하여 다른 기능을 실행했습니다 getopt
.
getopt_test ()
{
shortopts="Vuhv::H::w::e::n::l::C:"
shortopts="${shortopts}bgcrmo"
longopts="version,usage,help,verbosity::"
longopts="${longopts},heading::,warning::,error::"
longopts="${longopts},blu,grn,cyn,red,mgn,org"
opts=$( getopt -o "$shortopts" -l "$longopts" -n "${0##*/}" -- "$@" )
print-args "\$@:" "$@"
print-args "opts:" "$opts"
set -- "$opts"
print-args "set -- \"$opts\"" "$@"
eval set -- "$opts"
print-args "eval set -- \"$opts\"" "$@"
}
그 결과는 다음과 같습니다
getopt_test --warning=3 "foo'bar" "Gunga Din"
$@:
1. |--warning=3|
2. |foo'bar|
3. |Gunga Din|
opts:
1. | --warning '3' -- 'foo'\''bar' 'Gunga Din'|
set -- "$opts"
1. | --warning '3' -- 'foo'\''bar' 'Gunga Din'|
eval set -- "$opts"
1. |--warning|
2. |3|
3. |--|
4. |foo'bar|
5. |Gunga Din|
표시된 대로 getopt의 결과는 위치 매개변수가 재배열된 항목입니다. 이는 옵션 구문 분석 및 처리를 위해 eval set -- "$opts"
문자열의 위치 매개변수를 opts
5개 항목으로 분할해야 함을 나타냅니다.
답변1
아이디어는 매개변수를 전처리하고 각 매개변수를 --context
처리할 수 있는 매개변수로 변경하는 것입니다 -C
. getopts
나는 이것이 작동할 것이라고 생각하지만 GNU 스타일의 긴 옵션은 format에 대한 인수를 취할 수도 있으며 --context=foobar
여기서는 귀하의 구성이 지원하지 않습니다. 사용자는 여기서 이 특정 도구에 두 가지 다른 매개변수가 필요하다는 것을 알아야 합니다 --context
foobar
. 아니면 전처리를 더 복잡하게 만들어야 합니다.
로 시작하는 모든 매개변수를 확인하고 싶을 수도 있습니다 --
. 그렇지 않으면 예를 들어 오타가 그대로 발생하고 알 수 없는 옵션에 대한 불만 사항이 표시됩니다 --cotnext
. getopts
(또는 더 나쁜 경우 잘못된 옵션이 활성화됩니다.)
그런데 사용법이 맞는지 알고 싶습니다
set -- "${aggr[@]}"
.아니면 다음(eval 사용)이 더 적합합니까?
set -- "${aggr[@]}"
배열의 요소를 다른 단어로 확장하고 해당 단어를 위치 매개변수에 할당합니다. 각 배열 요소는 정확히 하나의 위치 매개변수가 되며 변경할 필요가 없습니다.
eval set -- "${aggr[@]}"
배열의 모든 요소는 확장된 다음 공백으로 연결되고 앞에 추가되며 set --
결과는 셸 명령으로 평가됩니다. 즉, 배열 요소 abc def
, $(date >&2)
, 가 있는 경우 ghi'jkl
명령은 다음과 같습니다.
set -- abc def $(date >&2) ghi'jkl
abc
이는 및 두 개의 다른 인수로 끝나고 def
작은 따옴표만으로 구문 오류가 발생한다는 점을 제외하고 날짜를 stderr에 인쇄합니다.
eval
쉘에 대한 입력으로 인용된 출력을 생성하도록 설계된 것이 있는 경우 이를 사용하는 것이 적절합니다.
Linux를 사용 중이고 이식성에 관심이 없다면 roaima가 설명에서 제안한 대로 수행하고 util-linux 버전 getopt
( s
)을 사용할 수 있습니다. 긴 옵션도 지원하며 사용 방법을 보여주는 답변이 있습니다.getopt, getopts 또는 수동 구문 분석 - 짧은 옵션과 긴 옵션을 모두 지원하려면 무엇을 사용해야 합니까?그리고이 답변그리고내 대답은 여기에 있다.
그런데, getopt
당신은 이렇게회의명령 eval
으로서 배열과 같은 목록이 아닌 단일 문자열을 출력으로 생성하는 것으로 제한되기 때문에 셸 따옴표를 사용하여 해당 문제를 해결합니다.
답변2
--foo
내장 함수를 사용 getopts
하여 인수를 -
짧은 옵션으로 추가하고 인수를 optstring에 전달하고 여기에서 실제 긴 옵션을 검색하여 스타일 긴 옵션을 구문 분석 할 수 있습니다 $OPTARG
. 간단한 예:
while getopts :sc:-: o; do
case $o in
:) echo >&2 "option -$OPTARG needs an argument"; continue;;
'?') echo >&2 "unknown option -$OPTARG"; continue;;
-) o=${OPTARG%%=*}; OPTARG=${OPTARG#"$o"}; OPTARG=${OPTARG#=};;
esac
echo "OPT $o=$OPTARG"
done
shift "$((OPTIND - 1))"
echo "ARGS $*"
script -c foo
그런 다음 또는 으로 사용할 수 있습니다 script --context=foo
.
짧은 옵션과 같은 긴 옵션도 확인하고 약어도 허용하려면 좀 더 복잡한 것이 필요합니다. 그러한 나쁜 쉘 스크립트를 과도하게 엔지니어링하는 것은 현명하지 않지만 예를 원한다면 다음과 같습니다.
short_opts=sc:
long_opts=silent/ch/context:/check/co # those who take an arg END with :
# override via command line for testing purposes
# if [ "$#" -ge 2 ]; then
# short_opts=$1; long_opts=$2; shift 2
# fi
while getopts ":$short_opts-:" o; do
case $o in
:) echo >&2 "option -$OPTARG needs an argument" ;continue;;
'?') echo >&2 "bad option -$OPTARG" ;continue;;
-) o=${OPTARG%%=*}; OPTARG=${OPTARG#"$o"}; lo=/$long_opts/
case $lo in
*"/$o"[!/:]*"/$o"[!/:]*) echo >&2 "ambiguous option --$o"; continue;;
*"/$o"[:/]*) ;;
*) o=$o${lo#*"/$o"}; o=${o%%[/:]*} ;;
esac
case $lo in
*"/$o/"*) OPTARG= ;;
*"/$o:/"*)
case $OPTARG in
'='*) OPTARG=${OPTARG#=};;
*) eval "OPTARG=\$$OPTIND"
if [ "$OPTIND" -le "$#" ] && [ "$OPTARG" != -- ]; then
OPTIND=$((OPTIND + 1))
else
echo >&2 "option --$o needs an argument"; continue
fi;;
esac;;
*) echo >&2 "unknown option --$o"; continue;;
esac
esac
echo "OPT $o=$OPTARG"
done
shift "$((OPTIND - 1))"
echo "ARGS $*"
그 다음에
$ ./script --context=33
OPT context=33
$ ./script --con=33
OPT context=33
$ ./script --co
OPT co=
$ ./script --context
option --context needs an argument