위치 매개변수 목록을 가져 와서 반복하고, 매개변수가 있는 플래그와 옵션을 구문 분석하고, 구문 분석 후 이를 제거하여 기본 매개변수만 남겨두는 bash
스크립트를 어디 선가 본 기억이 납니다. 그런 다음 스크립트에 의해 처리됩니다.case
shift
예를 들어, 명령줄을 구문 분석할 때 cp -R file1 -t /mybackup file2 -f
먼저 매개변수를 반복하고, 사용자가 디렉토리에 드롭을 요청했는지 식별하고 -R
, 대상을 지정 -t /mybackup
하고 강제로 복사한 다음 매개변수 목록에서 해당 매개변수를 제거하고 프로그램을 다음과 같이 -f
남겨둡니다. file1 file2
처리할 나머지 매개변수.
하지만 매번 보는 스크립트를 기억하거나 알아낼 수 없는 것 같습니다. 나는 단지 그렇게 할 수 있기를 원합니다. 나는 다양한 사이트를 인터넷 검색하고 내가 확인한 관련 페이지 목록을 첨부했습니다.
사이트의 한 질문은 "순서 독립적 옵션"에 대해 구체적으로 질문했지만 단일 답변이나 복제된 질문에 대한 답변은 옵션이 일반적인 인수와 혼합되는 위와 같은 상황을 고려하지 않습니다. 이 사람의 경우 특별 언급 이유순서와 상관없이옵션.
bash
내장 함수는 옵션이 아닌 첫 번째 인수에서 멈추는 것 같아서 getopts
해결책으로는 충분하지 않은 것 같습니다. 이것이 Wooledge BashFAQ 페이지(아래 참조)에서 매개변수를 재정렬하는 방법을 설명하는 이유입니다. 하지만 매개변수 목록이 매우 긴 경우에는 여러 배열을 만드는 것을 피하고 싶습니다.
shift
매개변수 목록 중간에서 단일 매개변수를 표시하는 것은 지원되지 않으므로 내가 원하는 것을 달성하는 간단한 방법이 무엇인지 잘 모르겠습니다 .
완전히 새로운 배열을 만들지 않고도 매개변수 목록의 중간에서 매개변수를 제거할 수 있는 솔루션이 있는지 듣고 싶습니다.
이미 본 페이지:
- http://mywiki.wooledge.org/ComplexOptionParsing#Rearranging_arguments
- http://mywiki.wooledge.org/BashFAQ/035
- 길고 짧은 명령줄 옵션을 얻으려면 bash 쉘 스크립트에서 getopts를 사용하십시오.
- http://wiki.bash-hackers.org/scripting/posparams
- http://wiki.bash-hackers.org/howto/getopts_tutorial
- $@에 있는 인수의 Bash 매개변수 사례
- Bash 스크립트에서 순서 독립적 옵션을 구현하는 표준 방법은 무엇입니까?
- 쉘 스크립트에서 스위치를 처리하는 방법은 무엇입니까?
답변1
POSIXly, 옵션 구문 분석은 --
첫 번째 비옵션(또는 비옵션 매개변수) 인수 중 먼저 오는 것에서 중지되어야 합니다. 그래서
cp -R file1 -t /mybackup file2 -f
file1
에 있으므로 cp
모든 file1
, -t
및 가 디렉터리 에 /mybackup
반복적으로 복사되어야 합니다 .file2
-f
그러나 GNU getopt(3)
( 옵션을 구문 분석하는 데 사용됨(여기서는 GNU 특정 옵션을 사용하기 때문에 cp
GNU를 사용함 ))는 환경 변수가 설정되지 않은 한 인수 뒤에 옵션을 허용합니다. 따라서 실제로 POSIX 옵션 스타일 구문 분석과 동일합니다.cp
-t
$POSIXLY_CORRECT
cp -R -t /mybackup -f -- file1 file2
getopts
GNU 쉘( )에서도 내장 쉘은 bash
POSIX 버전만 처리합니다. 또한 긴 옵션이나 선택적 매개변수가 있는 옵션도 지원하지 않습니다.
GNU와 같은 옵션을 구문 분석하려면 cp
GNU API를 사용해야 합니다 getopt(3)
. 이렇게 하려면 Linux의 경우 다음을 사용할 수 있습니다 getopt
(util-linux
이 명령 getopt
의 향상된 버전또한 다른 Unices에도 포팅되었습니다.FreeBSD).
이렇게 하면 getopt
옵션이 정식 방식으로 재정렬되어 루프를 통해 간단히 구문 분석할 수 있습니다 while/case
.
$ getopt -n "$0" -o t:Rf -- -Rf file1 -t/mybackup file2
-R -f -t '/mybackup' -- 'file1' 'file2'
일반적으로 다음과 같이 사용합니다.
parsed_options=$(
getopt -n "$0" -o t:Rf -- "$@"
) || exit
eval "set -- $parsed_options"
while [ "$#" -gt 0 ]; do
case $1 in
(-[Rf]) shift;;
(-t) shift 2;;
(--) shift; break;;
(*) exit 1 # should never be reached.
esac
done
echo "Now, the arguments are $*"
또한 getopt
GNU와 동일한 방식으로 옵션을 구문 분석한다는 점에 유의하세요 cp
. 특히 GNU 와 마찬가지로 긴 옵션을 지원하고(축약된 형식으로 입력) $POSIXLY_CORRECT
환경 변수를 존중합니다(설정 시 인수 후 옵션에 대한 지원이 비활성화됨) cp
.
gdb를 사용하고 수신된 매개변수를 인쇄하면 getopt_long()
매개변수를 작성하는 데 도움이 될 수 있습니다 getopt(1)
.
(gdb) bt
#0 getopt_long (argc=2, argv=0x7fffffffdae8, options=0x4171a6 "abdfHilLnprst:uvxPRS:T", long_options=0x417c20, opt_index=0x0) at getopt1.c:64
(gdb) set print pretty on
(gdb) p *long_options@40
$10 = {{
name = 0x4171fb "archive",
has_arg = 0,
flag = 0x0,
val = 97
}, {
name = 0x417203 "attributes-only",
[...]
getopt
그런 다음 다음과 같이 사용할 수 있습니다 .
getopt -n cp -o abdfHilLnprst:uvxPRS:T -l archive... -- "$@"
cp
GNU에서 지원하는 옵션 목록은 버전마다 변경될 수 있으며 옵션에 합법적인 값을 전달하는지 getopt
확인할 방법이 없다는 점을 명심하세요 .--sparse
답변2
따라서 인수가 처리될 때마다 처리해야 하는 인수 목록의 다음 숫자로 쉘 변수를 설정하고 0이 아닌 값을 반환할 getopts
것으로 예상하지 않습니다 . 값을 1로 설정 $OPTIND
하면 POSIX는 새 매개변수 목록이 허용되도록 지정합니다. 따라서 이는 단지 반환을 관찰하고, 실패한 반환에 대한 증가 카운터 더하기 기호를 저장하고 , 실패한 매개변수를 제거하고, 실패한 각 시도를 재설정합니다. 루프를 사용자 정의하거나 변수 에 저장하고 해당 부분을 .$OPTIND
getopts
getopts
$OPTIND
$OPTIND
opts "$@"
case
eval $case
opts() while getopts :Rt:f opt || {
until command shift "$OPTIND" || return 0
args=$args' "${'"$((a=${a:-0}+$OPTIND))"'}"'
[ -n "${1#"${1#-}"}" ]
do OPTIND=1; done 2>/dev/null; continue
}; do case "$opt" in
R) Rflag=1 ;;
t) tflag=1 ;
targ=$OPTARG ;;
f) fflag=1 ;;
esac; done
$args
런타임 시 처리되지 않은 모든 인수로 설정됩니다 getopts
... 그래서...
set -- -R file1 -t /mybackup file2 -f
args= opts "$@"; eval "set -- $args"
printf %s\\n "$args"
printf %s\\n "$@"
printf %s\\n "$Rflag" "$tflag" "$fflag" "$targ"
산출
"${2}" "${5}"
file1
file2
1
1
1
/mybackup
이것은 bash
, dash
, zsh
, ksh93
, mksh
...에 작동합니다. 글쎄, 나는 그 시점에서 시도를 포기했습니다. 각 셸에는 $[Rtf]flag
및 도 포함되어 있습니다 $targ
. 중요한 점은 getopts
처리하고 싶지 않은 매개변수의 모든 숫자가 유지된다는 것입니다.
옵션 스타일을 변경해도 아무런 차이가 없습니다. 이는 -Rf -t/mybackup
또는 와 유사하게 작동합니다 -R -f -t /mybackup
. 목록 중간, 목록 끝 또는 목록 시작 부분에서 작동합니다.
그럼에도 불구하고,가장 좋은 방법매개변수 목록 끝에 for 옵션을 붙여넣고 --
처리 shift "$(($OPTIND-1))"
실행이 끝나면 실행하세요 getopts
. 이 방법으로 처리된 모든 매개변수를 제거할 수 있습니다.그리고매개변수 목록의 끝을 유지합니다.
제가 좋아하는 것 중 하나는 장기 옵션을 단기 옵션으로 전환하는 것입니다. 저는 이 작업을 매우 비슷한 방식으로 수행하므로 이 답변을 쉽게 얻을 수 있습니다.앞으로난 달린다 getopts
.
i=0
until [ "$((i=$i+1))" -gt "$#" ]
do case "$1" in
--Recursive) set -- "$@" "-R" ;;
--file) set -- "$@" "-f" ;;
--target) set -- "$@" "-t" ;;
*) set -- "$@" "$1" ;;
esac; shift; done