여기서 `set --$args` 라인은 무엇을 하며 Zsh와 Bash 간에 다르게 동작하는 이유는 무엇입니까?

여기서 `set --$args` 라인은 무엇을 하며 Zsh와 Bash 간에 다르게 동작하는 이유는 무엇입니까?

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에서는 다르게 작동합니다. $foonull인 경우를 제외하고는 값으로 확장됩니다. 따라서 zsh에서는 위치 매개변수를 얻습니다.foofoo

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}

bashField Splittingcontent 에서 실행되면 $args4개의 문자열이 생성됩니다. $#이후에 위치 매개변수의 개수를 확인할 수 있습니다 set -- $args.

그렇다면 와일드카드를 끄도록 추가해야 합니다 bash.set -f

관련 정보