旧それなりブログの跡地、画像やスタイルやJSなどが壊れてることがあります。

シェルでループ時のデリミタを切り替えたい

2007年11月12日

ボーンシェルで、文字列をfor文に突っ込んでループするときの、分割文字の指定方法のことです。

本当は改行区切りの各文字列でループさせたいのに、文字列中の半角空白とかでも分割されてループしてしまう・・・と言う状況への対処です。

改行文字で”aaa bbb ccc” “AAA BBB CCC” “111 222 333″ の文字列でループさせたいのに、”aaa” “bbb” “ccc” … でループしてしまう例。

#!/bin/sh
SUBJECT="aaa bbb ccc
AAA BBB CCC
111 222 333"
for i in $SUBJECT
do
echo "----"
echo $i
done

出力

----
aaa
----
bbb
----
ccc
----
AAA
----
BBB
----
CCC
----
111
----
222
----
333

9回回ってしまいます。
なお、”$SUBJECT” という記述でfor文に入れると、逆に1回しかループしません。

対処法

#!/bin/sh
ORG_IFS=$IFS
MOD_IFS="
"
SUBJECT="aaa bbb ccc
AAA BBB CCC
111 222 333"
IFS=$MOD_IFS
for i in $SUBJECT
do
IFS=$ORG_IFS
echo "----"
echo $i
IFS=$MOD_IFS
done
IFS=$ORG_IFS

出力

----
aaa bbb ccc
----
AAA BBB CCC
----
111 222 333

OK-

ボーンシェルには$IFSという環境変数があって、これがfor文に渡す文字列のデリミタとして使用されます。
ので、それをfor文実行前に変えてやれば良いということです。
上記例で、ORG_IFSにこまめに戻しているのは、for文の中でまたfor文を使うとき用の対処です、必須じゃないっす。
参考: http://www.tsden.org/takamiti/shText/shText030.html (“IFS”でページ内検索をしてください)