getopt
구성을 사용하는 예는 Mac OSX와 함께 제공되는 버전의 맨페이지에 나와 있습니다 args=$(getopt optstring $*); set -- $args
. 여기서 뭐 하는 거야 set -- $args
?
또한 함수와 테스트 문자열을 고려하세요.
f () {
args=$(getopt o: $*)
set -- $args
for i; do
echo $i
done
}
f -o 123 xyz
Bash 3.2 및 4.3에서는 다음이 생성됩니다.
-o
123
--
xyz
그러나 Zsh 5.1에서는 다음을 생성합니다.
-o 123 -- xyz
차이의 원인은 무엇입니까? Zsh의 다른 단어 분할 동작 때문인가요, 아니면 다른 이유인가요? 인용 플래그와 매개변수 확장 플래그의 다양한 조합을 시도했지만 실제로 두 셸에서 무슨 일이 일어나고 있는지 파악할 수 없습니다.
답변1
이것은 나쁜 코드입니다. getopt
거의 사용할 수 없습니다. getopts
내장 셸을 사용하세요 (두 가지 장점이 있습니다. 작동한다는 것과 모든 POSIX 플랫폼에서 작동한다는 것입니다).
이것이 하는 일은 args=$(getopt optstring $*); set -- $args
:
- 각 명령줄 인수를 공백으로 분할하고 공백으로 구분된 단어 목록으로 바꿉니다.
- 각 결과 단어를 가져와서 와일드카드 패턴으로 해석합니다. 패턴이 하나 이상의 파일과 일치하는 경우 패턴을 일치하는 파일 목록으로 바꿉니다.
- 결과 단어 목록을
getopt
명령에 전달합니다. - 명령의 출력을
getopt
변수에 저장합니다args
. 이는 공백으로 구분된 명령줄 인수, 옵션 및 해당 인수,--
옵션이 아닌 피연산자 로 순서가 변경된 문자열입니다 . - 이 문자열을 공백으로 분할하고, 각 단어를 와일드카드 패턴으로 해석하고, 패턴을 일치하는 파일 목록(있는 경우)으로 바꿉니다.
- 결과 목록을 위치 인수로 사용합니다.
Bourne/POSIX 스타일 쉘에서는 $foo
"split+glob" 연산자입니다.변수 값을 얻으려면 큰따옴표가 필요합니다."$foo"
. 그러나 zsh에서는 다르게 작동합니다. $foo
null인 경우를 제외하고는 값으로 확장됩니다. 따라서 zsh에서는 위치 매개변수를 얻습니다.foo
foo
Split+glob 연산자의 첫 번째 사용은 다음과 같이 작성하여 피할 수 있습니다 getopt optstring "$@"
. 이렇게 하면 위치 인수가 정확하게 전달됩니다 getopt
. 그러나 출력을 구문 분석할 때 공백이 인수를 구분하는 데 사용되므로 getopt
분할은 불가피합니다(와일드카드를 비활성화할 수 있음) . getopt
문제는 출력이 모호하다는 것입니다 . 매개변수의 공백과 구분 기호로 추가된 getopt
공백을 구별할 수 있는 방법이 없습니다 .getopt
이를 수행하는 올바른 방법은 getopts
튼튼하고 휴대 가능합니다.
while getopts optstring OPTLET; do
# We got the option -$OPTLET
case $OPTLET in
…
esac
done
shift $((OPTIND-1))
# Now the positional parameters are just the non-option operands
¹ 적어도 BSD 버전. GNU 버전에는 이를 사용할 수 있도록 기능이 추가되었습니다.
답변2
set -- $args
의 내용을 기반으로 위치 매개변수를 설정합니다 $args
. 이제 zsh
다른 POSIX 셸과 다른 동작을 갖게 됩니다 .
zsh
구현되지 않아서필드 분할기본적으로 내용인 문자열을 얻습니다 $args
. bash
(및 다른 POSIX 셸)과 동일한 동작을 얻으려면 명시적으로 분할을 호출해야 합니다 .
set -- ${=args}
bash
Field Splitting
content 에서 실행되면 $args
4개의 문자열이 생성됩니다. $#
이후에 위치 매개변수의 개수를 확인할 수 있습니다 set -- $args
.
그렇다면 와일드카드를 끄도록 추가해야 합니다 bash
.set -f