shellのfor文について

最近技術系のことをしっかりまとめる時間が減ってきた。とりあえず小粒なものを書いておこうと思う。

2ヶ月前くらいに、AからJまで10個のアルファベットを順に取り出したいことがあった。つまりこういうことがしたい。

grep 'A' something.dat | some_command | ...
grep 'B' something.dat | some_command | ...
grep 'C' something.dat | some_command | ...
# ...
grep 'J' something.dat | some_command | ...

これを行コピーして書き換える者は「怠惰」ではない。 一応、bashには配列があるが、文法が微妙に複雑で、使おうと思った時は大抵忘れてしまっている。結局毎回「bash 配列」などで検索する羽目になる。

declare -a alphabets=("a" "b" "c")

これはわかりにくくないか?

ところで、bashforは意外と柔軟だ。

for a in A B C D E F G H I J; do
    grep ${a} something.dat | some_command | ...
done

これが動く。

まあA B C D E F G H I Jを打つのは面倒なことに変わりはない。個人的には、普段ループに使っているseqで動けば一番いいのだが、と思っていた。 例えばこれは以下のようにすれば何とかなるだろう……と思ったが動かなかった。

for i in `seq 65 74`; do
    grep $(printf "%c" ${i}) something.dat | some_command | ...
done

どうやらこうすると最初の1文字目が出力されるだけでASCIIコードに対応する文字が出るわけではないようだ。 他にはhexにしてから0x4cなどのようにして変換させるという方法があるが、どんどん可読性が落ちていってしまう。

そして最近、以下が動くことを知った。

for a in {A..J}; do
    grep ${a} something.dat | some_command | ...
done

最初の苦労は何だったんだ?

その上、以下のようなことが起きる。

$ for a in {A..C}{1..3}; do
    echo ${a}
done
A1
A2
A3
B1
B2
B3
C1
C2
C3

今までの苦労を返して欲しい。

ところでfishでこれをする方法を探したが、どうもなさそうに見える。かなしい。

Better document differences from bash · Issue #2382 · fish-shell/fish-shell · GitHub