내가 이 답을 찾고 있었을 때https://stackoverflow.com/a/11065196/4706711--something
예를 들어 매개변수를 사용하는 방법 이나 -s
응답 스크립트에 대해 묻는 일부 질문을 알아내려면 다음을 수행하세요 .
#!/bin/bash
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
-n 'example.bash' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument \`$2'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do echo '--> '"\`$arg'" ; done
먼저, shift
다음 줄의 프로그램은 무엇을 수행합니까?
-a|--a-long) echo "Option a" ; shift ;;
eval
그렇다면 다음 명령줄을 사용하는 목적은 무엇입니까?
eval set -- "$TEMP"
위에서 언급한 스크립트의 해당 줄에 주석을 달았고 다음과 같은 응답을 받았습니다.
$ ./getOptExample2.sh -a 10 -b 20 --a-long 40 -charem --c-long=echi
Param: -a
Option a
Param: 10
Internal error!
하지만 주석을 제거하면 매력처럼 작동합니다.
Option a
Option b, argument `20'
Option a
Option c, argument `harem'
Option c, argument `echi'
Remaining arguments:
--> `10'
--> `40'
답변1
옵션을 구문 분석할 때 해야 할 많은 작업 중 하나 getopt
는 옵션이 아닌 인수가 마지막에 있고 결합된 짧은 옵션이 분리되도록 인수를 재배열하는 것입니다. ~에서man getopt
:
Output is generated for each element described in the previous section.
Output is done in the same order as the elements are specified in the
input, except for non-option parameters. Output can be done in
compatible (unquoted) mode, or in such way that whitespace and other
special characters within arguments and non-option parameters are
preserved (see QUOTING). When the output is processed in the shell
script, it will seem to be composed of distinct elements that can be
processed one by one (by using the shift command in most shell
languages).
[...]
Normally, no non-option parameters output is generated until all
options and their arguments have been generated. Then '--' is
generated as a single parameter, and after it the non-option parameters
in the order they were found, each as a separate parameter.
이 효과는 옵션이 루프를 처리하는 코드에 반영됩니다.가설모든 옵션 인수(옵션 인수 포함)는 처음에 단독으로 나타나고 마지막에 옵션이 아닌 인수가 옵니다.
따라서 TEMP
재배열, 인용, 분할 및 eval set
스크립트 매개변수 만들기 사용 옵션이 포함되어 있습니다.
왜 eval
? 의 출력을 안전하게 변환하는 방법이 필요합니다 getopt
. 이는 공백, '
( "
따옴표) *
등과 같은 특수 문자를 안전하게 처리한다는 것을 의미합니다 . 이렇게 하려면 getopt
셸에서 해석할 수 있도록 출력에서 해당 항목을 이스케이프 처리하세요. 그렇지 않은 경우 eval
유일한 옵션은 이지만 set $TEMP
필드 분할 및 와일드카드를 통해서만 이를 수행할 수 있으며 셸의 전체 구문 분석 기능은 사용할 수 없습니다.
두 가지 주장이 있다고 가정해 보겠습니다. 필드 분할만 사용하면 매개변수에서 사용 가능한 문자를 추가로 제한하지 않고 이 두 단어를 별도의 단어로 처리할 수 없습니다(예를 들어 IFS를 로 설정한 경우 매개변수에서 사용할 :
수 없습니다 ). :
따라서 이러한 문자를 이스케이프 처리하고 쉘이 해당 이스케이프를 해석하도록 할 수 있어야 합니다. 이것이 바로 eval
이것이 필요한 이유입니다. 뭔가 크게 잘못되지 않는 한 getopt
안전할 것입니다.
의 경우 shift
항상 하는 일을 수행합니다. 첫 번째 인수를 제거하고옮기다모든 매개변수( $2
현재 내용은 $1
)입니다. 이렇게 하면 처리된 인수가 제거되므로 이 루프 후에는 옵션이 아닌 인수만 남게 되며 $@
옵션에 대해 걱정할 필요 없이 편리하게 사용할 수 있습니다.
답변2
다음으로, 다음 줄에서 eval 명령을 사용하는 목적은 무엇입니까?
eval set -- "$TEMP"
util-linux 버전 getopt
에서 생성된 출력은 셸에 대한 입력으로 사용될 수 있습니다. 공백이 포함된 문자열을 따옴표로 묶고 리터럴 따옴표 및 기타 특수 문자의 이스케이프를 처리합니다.
예를 들어
$ getopt -o a:b -- -a 'foo bar' -b "single'quotes'here"
-a 'foo bar' -b -- 'single'\''quotes'\''here'
따옴표는 일반 확장의 결과로 처리되지 않지만 전체 구문 분석이 필요합니다. 그게 다야 eval
.
출력이 에 할당된 경우 $tmp
, 이후의 eval set -- "$tmp"
위치 인수 $1
, $2
, ... 는 -a
, foo bar
-b
--
single'quotes'here
및 를 포함하며 루프에서 비교적 쉽게 처리할 수 있습니다.
을 사용하면 set -- $tmp
위치 매개변수가 , 등으로 설정됩니다 -a
. 이는 원하는 것이 아닙니다. (인수 중 하나가 예를 들어인 경우 맨 위에 와일드카드가 표시됩니다 .)'foo
bar'
*
질문은 다음과 같습니다.변수에 저장된 명령을 어떻게 실행할 수 있나요?, 두 경우 모두 임의의 문자열 목록이 포함됩니다.
이 동작은 getopt
쉘 인용 출력을 생성합니다.util-linux 버전에만 해당그것은. 다른 시스템에는 일반적으로 getopt
사용되는아니요 eval
, 그리고 공백을 포함하거나 와일드카드처럼 보이는 인수를 행복하게 중단합니다. 이와 마찬가지로 출력에서 foo bar
단일 인수가 무엇인지 알 수 있는 방법이 없습니다 .
$ getopt a:b -a 'foo bar' -b "single'quotes'here"
-a foo bar -b -- single'quotes'here
를 사용할 때 먼저 / 옵션을 getopt
사용하여 임의의 문자열을 처리할 수 있는 안전한 버전이 있는지 확인하세요.-T
--test
답변3
오류가 발생하면 스크립트는 제대로 작동합니다 -a 10
. 이 -a
옵션에는 이 스크립트에 매개변수가 필요하지 않습니다. 만 사용해야 합니다 -a
.
매뉴얼 페이지에 설명된 변환은 다음과 같습니다.
shift [n]
The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is
0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater
than $# or less than zero; otherwise 0.
따라서 기본적으로 -a를 제거하고 나머지 인수를 이동하여 다음 주기에서 두 번째 인수가 $1이 되도록 합니다.
--
매뉴얼 페이지에도 설명되어 있습니다.
-- A -- signals the end of options and disables further option processing. Any arguments after the -- are treated as filenames and arguments. An argument of - is equivalent to --.