POSIX for 루프가 ; 내에서 `for name do`(목록에 단어 없음) 구문을 허용하는 이유는 무엇입니까?

POSIX for 루프가 ; 내에서 `for name do`(목록에 단어 없음) 구문을 허용하는 이유는 무엇입니까?

for 루프 구문을 이해하려고 합니다.POSIX 쉘 구문 규칙:

for_clause       : For name                                      do_group
                 | For name                       sequential_sep do_group
                 | For name linebreak in          sequential_sep do_group
                 | For name linebreak in wordlist sequential_sep do_group

마지막 항목(거의 기본값)과 처음 두 항목은 posix를 인용하여 의미가 있습니다.

생략됨: in word... 다음과 동일해야 합니다. in "$@"

따라서 처음 두 개는 쉘 스크립트의 매개변수를 반복하는 것입니다.

for 루프가 for name in; do echo $name; done. 나는 여전히 쉘 스크립트의 매개변수를 반복하는 것이라고 생각했지만 작은 스크립트를 작성하는 것은 그렇지 않은 것 같습니다. for 루프가 약간 무시된 것 같습니다. 그렇다면 세 번째 변형의 목적은 무엇입니까?

답변1

다음과 같이 정의 하면 wordlist됩니다.

wordlist         : wordlist WORD
                 |          WORD

그래서하나 이상말하지만 for var in ...; do ...; done루프는 반복될 수 있습니다.0 이상For name linebreak in sequential_sep do_group, 따라서 상황을 다루어야 합니다.단어 0개.

wordlist~로써 정의 된0개 이상의 단어:

wordlist         : wordlist WORD
                 | /* empty */

덜 혼란스러울 수도 있습니다.

당신이 보면SUSv2, 가지다:

 for_clause       : For name linebreak                            do_group
                  | For name linebreak in wordlist sequential_sep do_group
 wordlist         : wordlist WORD
                  |          WORD

이는 빈 목록이 허용되지 않음을 의미합니다. 따라서 SUSv3에서는 다음을 추가하여 누락을 수정한 것 같습니다.

For name linebreak in sequential_sep do_group

정의를 변경하는 대신 wordlist.


여기서는 쉘 언어 구문에 대해 이야기하고 있으므로 어디/확장하면 빈 목록이 발생할 수 있는지에 관한 것이 아닙니다 for i in $var; do ...; done. 이는 모두 쉘 언어의 POSIX 형식화에 있는 WORD 태그입니다.for i in $(some cmd); do ...; done$var$(some cmd)$var$(some cmd)

우리를얘기하지만 for i in; do ...; done실제로는 그렇지 않습니다단어in와 ~ 사이에있는 do.

코드가 특별히 유용하지 않다는 데 동의합니다. 명시적으로 아무것도 반복하지 않는 루프를 작성할 이유가 없습니다. 생각할 수 있는 몇 가지 이유는 다음과 같습니다.

생성된 코드:

if ...; then
  list=' "foo" "bar baz" "$var" '
else
  list=
fi

eval '
  for i in '"$list"'; do
    printf "%s\n" "$i"
  done
'

또는 sh스크립트를 생성하고 for명시적 매개변수에 대한 루프를 구성하는 모든 것입니다.

또는 일부 코드를 주석 처리합니다.

for commented_out in; do
  this code is commented out
done

이와 같은 동안 :

:||:<<'EOF'
  this code is commented out and (harmless) even
  if it contains invalid syntax
EOF

더 관용적 일 것입니다.

표준을 수정하게 된 변경 요청은 찾지 못했지만 주로 기존의 모든 쉘 구현이 허용하기 때문에 변경한 것 같으니 for i in; do ...; done표준에서 금지할 필요는 없습니다.

Bourne 쉘과 Korn에서 시작하는 대부분의 구현(이것은 주목할 만한 예외입니다)처럼 이를 허용하지 않을 타당한 이유가 없음에도 불구하고 if then ...; else ...; fiNor if; then ...; else ...; fiNor 1을 허용하지 않는다는 것을 알게 될 것입니다 if ...; then;else ...; fi(그러나 분명히 그렇습니다). 도입되었으므로 POSIX 사양 기반 쉘이 실제로 차단됩니다.if $empty; then $empty; else $empty; fizshsh


1 실제로 !파이프의 종료 상태를 무효화하는 키워드가 없는 Bourne 쉘에서는 Bourne 쉘이 빈 섹션을 허용하지 않기 때문에 섹션에 명시적인 null 명령을 사용하여 대신 if cmd; then :; else command if cmd fails; fi작성 해야 합니다 .if ! cmd; then command if cmd fails; fi:thenthen

답변2

예를 들어 이러한 동작의 이유를 설명하는 것이 가장 좋습니다. 호출된 변수가 있고 ${items}해당 변수의 각 단어에 대해 함수를 호출해야 하지만 경우에 따라 빈 문자열로 평가될 수 있다고 가정해 보겠습니다 .

POSIX 호환 동작의 경우 다음을 사용하면 됩니다.

for x in ${items} ; do
   do_something(x)
done

여기서는 평가 결과가 빈 문자열인지 여부는 중요하지 않습니다 ${items}. 빈 문자열이면 루프는 반복할 항목이 없으며 그냥 건너뛰게 되기 때문입니다.

그러나 쉘이 빈 단어 목록 대소문자를 다르게 처리하는 경우(전혀 처리하지 않거나 없는 형식 중 하나와 동일 in) 다음이 필요합니다(적어도).

if [ -n "${items}" ]; then
    for x in ${items} ; do
        do_something(x)
    done
fi

따라서 길이를 알 수 없는 빈 항목 목록을 반복해야 하는 비교적 일반적인 상황에서 이 동작은 (적어도) 어느 정도 들여쓰기 및 추가 조건 확인을 절약합니다. 항목 모음(예: Python 또는 JavaScript)을 반복하는 for 루프가 있는 다른 많은 언어는 정확히 동일한 방식으로 동작합니다. 루프에 제공할 변수(또는 리터럴)를 명시적으로 요청하는 반면, 이를 수행하는 쉘 스크립트는 반복할 항목의 리터럴 목록이 정의되는 방식(즉, 빈 목록은 따옴표가 없는 빈 문자열임) 때문에 존재하지 않는 것 같습니다.

관련 정보