명령에서 한 줄에 하나씩 반복하려는 문자열 목록이 포함된 변수가 있습니다 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
'