Bourne Shell 및 zsh에서 수정되지 않은 채 작동하는 변수의 단어나 줄을 반복하는 "for" 구문이 있습니까?

Bourne Shell 및 zsh에서 수정되지 않은 채 작동하는 변수의 단어나 줄을 반복하는 "for" 구문이 있습니까?

명령에서 한 줄에 하나씩 반복하려는 문자열 목록이 포함된 변수가 있습니다 for...in...do...done.

Bourne Shell과 zsh 사이를 자주 전환합니다. 내가 아는 한, zsh는 기본적으로 Bern 쉘에서 줄 바꿈이나 공백으로 문자열에서 단어를 분리하지 않습니다. 따라서 zsh와 같은 명령 for list_item in $list; do...은 실패하지만 bourne 쉘에서는 작동하거나 변수 대신 리터럴 텍스트를 사용할 수 있습니다. 명령에서 변수를 사용하고 참조하려고 시도했지만 IFS=진전이 없는 것 같습니다.

쉽게 구현할 수 있도록 두 셸 모두에서 수정되지 않은 상태로 작동하는 문자열의 단어/줄을 반복하는 단일 구문이 있습니까? 그렇지 않다면 모범 사례는 무엇입니까?

답변1

options 를 사용하여 bash와 유사하게 zsh의 토큰화 동작을 명시적으로 설정하면 bash와 zsh 간의 일관된 동작을 얻을 수 있습니다 shwordsplit. 예를 들어:

set -o shwordsplit

var='foo bar baz'
for item in $var; do
    echo "$item"
done

IFS이로 인해 zsh는 bash와 마찬가지로 내부 필드 구분 기호( )를 기반으로 토큰화를 수행합니다 .

답변2

Bourne 쉘은 더 이상 사용되지 않으며 POSIX 이전 버전이며 POSIX와 호환되지 않습니다. Bourne 셸을 기반으로 한 몇 가지 POSIX 호환 셸이 있습니다. 원래 Korn 셸(ksh93 재작성 전)(sh의 POSIX 사양은 해당 셸을 기반으로 함)과 bosh는 OpenSolaris sh(자체는 SysV 셸을 기반으로 함)를 기반 으로 합니다. Bourne 쉘을 기반으로 한 일부 수정 사항).

FreeBSD sh는 Almquist 셸(그 자체는 SysV 셸의 대부분 호환 가능한 오픈 소스 복제본이며 ksh 등의 일부 확장 기능을 포함 $(...))을 기반으로 하지만 POSIX와 호환되도록 수정되었습니다.

POSIX에서는 sh루프의 행을 반복하려면 for분할+glob을 사용할 수 없습니다. 개행은 IFS가 하나 이상의 개행 시퀀스를 분할하는 구분 기호 역할을 하는 공백 문자이므로 다음과 같습니다.

IFS='
' # split on newline
set -o noglob # disable the glob part
for line in $multiline_string; do
  printf '<%s>\n' "$line"
don

빈 줄은 건너뜁니다. 또한 zsh따옴표가 없는 매개변수 확장은 분할되거나 와일드카드로 표시되지 않으므로 해당 위치에 있어야 합니다 emulate sh.

"$@"다음 줄을 사용하여 배열을 구성 할 수 있습니다 .$multiline_string

NL='
'
set --
while [ -n "$multiline_string" ]; do
  line=${multiline_string%%"$NL"*}
  set -- "$@" "$line"
  multiline_string=${multiline_string#"$line"}
  multiline_string=${multiline_string#"$NL"}
done

for line do
  printf '<%s>\n'
done

또는:

printf '%s\n' "$multiline_string" | {
  set --
  while IFS= read -r line; do
    set -- "$@" "$line"
  done
  for line do
    printf '<%s>\n' "$line"
  done
}

for또는 다음을 사용하여 반복 쉘 코드를 작성할 수 있습니다 .

eval '
  for line in '"$(
    awk -v q="'" -F '\n' -v ORS=' ' -- '
      BEGIN {
        n = split(ARGV[1], line)
        for (i = 1; i < n; i++) {
          gsub(q, "&\\\\&&", line[i])
          print q line[i] q
        }
      }' "$multiline_string")"'; do
    printf "<%s>\n" "$line"
  done
'

관련 정보