이 Bash 루프를 변환하고 싶습니다.
x="one two three"
for i in ${x}
do
echo ${i}
done
이런 식으로 Bash와 zsh를 함께 사용하십시오
이 솔루션은 다음과 같이 작동합니다.
x=( one two three )
for i in ${x[@]}
do
echo ${i}
done
어쨌든 x
문자열에서 배열로 수정 중입니다.
$x
zsh가 문자열이고 Bash와 호환되는 방식으로 zsh에서 반복하는 방법이 있습니까?
zsh가 Bash를 에뮬레이트할 수 있다는 것을 알고 있지만 setopt shwordsplit
설정할 수는 없습니다.애드 혹for 루프는 Bash에서 작동하지 않기 때문입니다.
`
답변1
$x가 문자열이고 Bash와 호환되는 경우 zsh에서 $x를 반복하는 방법이 있습니까?
예! . var 확장은 zsh에서 (기본적으로) 분할되지 않지만명령 확장자는 다음과 같습니다.. 따라서 Bash와 zsh 모두에서 다음을 사용할 수 있습니다.
x="one two three"
for i in $( echo "$x" )
do
echo "$i"
done
실제로 위 코드는 모든 Bourne 쉘 자손에서 동일하게 작동합니다(그러나 원래 Bourne에서는 작동하지 않으므로 변경하여 작동하도록 하십시오) $(…)
.`…`
위 코드에는 여전히 와일드카드 및 에코 사용과 관련된 몇 가지 문제가 있습니다. 계속 읽어보세요.
zsh에서는 var 확장과 같은 것이 $var
기본적으로 분할되지 않습니다(글로브도 마찬가지).
이 코드는 zsh에서 문제 없이 작동합니다(pwd의 모든 파일로 확장되지는 않음).
var="one * two"
printf "<%s> " ${var}; echo
그러나 var는 IFS 값으로 나누어지지 않습니다.
zsh의 경우 다음 방법 중 하나를 사용하여 IFS에서 분할을 수행할 수 있습니다.
1. Call splitting explicitly: `echo ${=var}`.
2. Set SH_WORD_SPLIT option: `set -y; echo ${var}`.
3. Using read to split to a list of vars (or an array with `-A`).
그러나 이러한 옵션 중 어느 것도 bash(또는 해당 문제에 대해 ksh를 제외한 다른 쉘 -A
)로 이식 가능하지 않습니다.
두 쉘에서 공유하는 이전 구문을 사용하면 read
도움이 될 수 있습니다.
하지만 이는 다음에만 적용됩니다.문자 구분 기호(IFS 아님) 입력 문자열에 구분 기호가 있는 경우에만 다음과 같습니다.
# ksh, zsh and bash(3.0+)
t1(){ set -f;
while read -rd "$delimiter" i; do
echo "|$i|"
done <<<"$x"
}
$1
하나는 어디에 있습니까?캐릭터분리 기호.
*
?
여전히 와일드카드 문자( , 및 ) 확장이 적용되므로 [
이 필요합니다. set -f
또한 배열 변수를 설정할 수도 있습니다 outarr
.
# for either zsh or ksh
t2(){ set -f; IFS="$delimiter" read -d $'\3' -A outarr < <(printf '%s\3' "$x"); }
bash도 같은 생각을 가지고 있습니다.
# bash
t3(){ local -; set -f; mapfile -td "$1" outarr < <(printf '%s' "$x"); }
set -f
Bash 기능에서 복원된 효과를 사용하십시오 local -
.
이 개념은 대시와 같은 제한된 쉘로 확장될 수도 있습니다.
# valid for dash and bash
t4(){ local -; set -f;
while read -r i; do
printf '%s' "$i" | tr "$delimiter"'\n' '\n'"$delimiter"; echo
done <<-EOT
$(echo "$x" | tr "$delimiter"'\n' '\n'"$delimiter")
EOT
}
아니요 <<<
, 아니요 <(…)
, 아니요 read -A
또는 readarray
사용되었지만 작동합니다(예:캐릭터입력에 공백, 줄 바꿈 및/또는 제어 문자를 포함하는 구분 기호입니다.
하지만 간단히 이렇게 하는 것이 훨씬 쉽습니다.
t9(){ set -f; outarr=( $(printf '%s' "$x") ); }
안타깝게도 zsh는 그 local -
값을 이해하지 못하므로 다음과 같이 복원해야 합니다.set -f
t99(){ oldset=$(set +o); set -f; outarr=( $( printf '%s' "$x" ) ); eval "$oldset"; }
위의 함수는 다음을 통해 호출할 수 있습니다.
IFS=$1 delimiter=$1 $2
여기서 첫 번째 매개변수 $
는 구분 기호(및 IFS)이고 두 번째 매개변수는 호출할 함수(t1, t2, ... t9, t99)입니다. 이 호출은 함수 호출 중에 IFS 값만 설정하고 호출된 함수가 종료되면 원래 값으로 반환합니다.
답변2
if type emulate >/dev/null 2>/dev/null; then emulate ksh; fi
zsh sh_word_split
에서는 emulate
.
답변3
eval (=evil)을 사용하는 것이 두렵지 않다면:
x="one two three"
eval "x=($x)"
for i in ${x[@]}; do
echo $i
done