zshとbashの文字列を繰り返す

zshとbashの文字列を繰り返す

この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文字列から配列に変更しています。

$xzshが文字列で、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 -fBash機能で復元された効果を使用してください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)であり、2番目のパラメータは呼び出す関数(t1、t2、... t9、t99)です。この呼び出しは、関数呼び出し中にIFS値のみを設定し、呼び出された関数が終了したときに元の値として返します。

答え2

if type emulate >/dev/null 2>/dev/null; then emulate ksh; fi

zshsh_word_splitではemulate

答え3

eval(= evil)を使用するのが怖くない場合:

x="one two three"
eval "x=($x)"
for i in ${x[@]}; do 
    echo $i
done

関連情報