bashとzshでの配列の添え字と判別について
zshというシェルはbash互換の部分が多いのだが、配列の要素を個別に参照するときの番号(添え字)が異なることが分かった。
zshの配列は1番から
ARRAY=("aaa" "bbb" "ccc" "ddd" "eee") printf "0:%s 1:%s 2:%s 3:%s 4:%s 5:%s\n" ${ARRAY[0]} ${ARRAY[1]} ${ARRAY[2]} ${ARRAY[3]} ${ARRAY[4]} ${ARRAY[5]}
このスクリプトを実行すると
(bashの場合) 0:aaa 1:bbb 2:ccc 3:ddd 4:eee 5: (zshの場合) 0:aaa 1:aaa 2:bbb 3:ccc 4:ddd 5:eee
となり、zshでの番号がずれている(1番からになる)ことが分かる。
(2009/4/19)トラックバックを頂いて、相手の方のコメントが気になったので、再び実験を行った。まず、上のスクリプトを実行してみたところ、両方とも
0:aaa 1:bbb 2:ccc 3:ddd 4:eee 5:
となってしまった。バージョンは
$ bash --version GNU bash, version 3.2.19(2)-release (x86_64-mandriva-linux-gnu) Copyright (C) 2005 Free Software Foundation, Inc. $ zsh --version zsh 4.3.6 (x86_64-mandriva-linux-gnu)
となっている。次に
ファイル名: test.sh
ARRAY=("aaa" "bbb" "ccc" "ddd" "eee") printf "0:[%s] 1:[%s] 2:[%s] 3:[%s] 4:[%s] 5:[%s]\n" ${ARRAY[0]} ${ARRAY[1]} ${ARRAY[2]} ${ARRAY[3]} ${ARRAY[4]} ${ARRAY[5]} echo "[${ARRAY[0]}|${ARRAY[1]}|${ARRAY[2]}|${ARRAY[3]}|${ARRAY[4]}|${ARRAY[5]}]"
のようにしてもう少し詳しく調べてみた。
$ bash test.sh 0:[aaa] 1:[bbb] 2:[ccc] 3:[ddd] 4:[eee] 5:[] [aaa|bbb|ccc|ddd|eee|] $ zsh test.sh 0:[aaa] 1:[bbb] 2:[ccc] 3:[ddd] 4:[eee] 5:[] [|aaa|bbb|ccc|ddd|eee]
zshにおけるprintfでの出力のされ方はやはり変わっている。また、0番の項目を取り出そうとしても空で取り出せないという違いもあった。個別に取り出してみると、添え字が1番からなのは変わらなかった。なお
ファイル名: test2.sh
ARRAY=("aaa" "bbb" "ccc" "ddd" "eee") for X in ${ARRAY[*]}; do echo ${X} done
for文での処理では番号のずれを気にせず書けることも分かった。
$ bash test2.sh aaa bbb ccc ddd eee $ zsh test2.sh aaa bbb ccc ddd eee
bashとzshの判別例
下のコードでは、bashもしくはzshを使用しているとき*1に、その名前を表示する。他のシェルで実行すると「unsupported shell」を表示する。
if test -n "${BASH_VERSION:-}"; then echo bash else if test -z "${ZSH_VERSION:-}"; then echo "unsupported shell" exit 1 else # 配列の添え字に関する処理ではzsh用の処理はなく、else節は書かない echo zsh fi fi
このコードではzshの場合にelse節の処理が実行されるが、下で紹介しているコードのように、「zshの場合には何もしない(else節を書かない)」という場合があるため、この形で記述した。
判別と要素ずらしを利用して、bash/zshの両方で同様に動作するようにする
bash/zshの両方で同じように動作させたいコードがあってその中で配列を使用する場合の解決策の1つとして、「bashのときに配列の0番に無意味なデータを入れて、要素を1ずつ後ろにずらす」という方法がある。
下のコードは、bash上でもzsh上でも同様の結果を出力する。
ARRAY=("aaa" "bbb" "ccc" "ddd" "eee") if test -n "${BASH_VERSION:-}"; then # bashのときに配列全体を1番からにずらす ARRAY=("" ${ARRAY[@]}) else if test -z "${ZSH_VERSION:-}"; then echo "unsupported shell" exit 1 fi fi # 個別に取り出し、同じように動作することを確認 printf "1:%s 2:%s 3:%s 4:%s 5:%s\n" ${ARRAY[1]} ${ARRAY[2]} ${ARRAY[3]} ${ARRAY[4]} ${ARRAY[5]} # 各要素についての反復処理も同様に動作 for X in ${ARRAY[*]}; do echo ${X} done
実行結果
1:aaa 2:bbb 3:ccc 4:ddd 5:eee aaa bbb ccc ddd eee
関連記事:
使用したバージョン: