前へ
次へ
投稿者: かいちょう
2012年2月12日 14:56
タグ:
シェルスクリプト
bash
read
/dev/stdin
シェルスクリプトでの標準入力の読み方
友の会のページにあまりにもシェルスクリプトの情報が少ないので反省している会長です。
先日、あるサイトで、「シェルスクリプトで標準入力を読むためにはreadコマンドを使う」ということを書いてあったのですが、ちょっと補足が必要だと思いました。
確かに、下のようにreadを使うと、標準入力を読むことができます。
ueda@uedaubuntu:~$ cat hoge.sh
#!/bin/bash
while read i ; do
#数字を読み込んで1足して出力する。
echo $((i+1))
done
実行するとこうなりますね。
ueda@uedaubuntu:~$ seq 1 10 | ./hoge.sh
2
3
4
5
6
7
8
9
10
11
/dev/stdinを使おう
でも、この方法は一番最後に、どうしようもないときにとるべき手段です。同じ機能を持つシェルスクリプトは、以下のように書くこともできます。シェルスクリプトというよりawkのスクリプトですが・・・。
ueda@uedaubuntu:~$ cat hoge2.sh
#!/bin/bash
awk '{print $1+1}' < /dev/stdin
「< /dev/stdin」が、標準入力からのリダイレクトになります。
この例の場合はawkの使い方を知っている必要がありますが、
論点はそのようなことではなく、
bashの変数に一行一行読み込むのは時間計算量の点で高コスト
行を変数に入れてしまうとその後コマンドでバッチ処理が行いにくくなる
別に/dev/stdinを使うことに比べて体裁がよいわけではない
という点にあります。計算量については、ちょっとしたことをするには問題にはなりません。
が、私ならびに友の会としては、「シェルスクリプトは遅い」といういわれのない評判につながるので無視できない問題ではあります。
コストは桁違い
さきほどのhoge.shとhoge2.shの時間を比較してみましょう。
ueda@uedaubuntu:~$ time seq 1 1000000 | ./hoge.sh > /dev/null
real 0m29.642s
user 0m24.542s
sys 0m5.992s
ueda@uedaubuntu:~$ time seq 1 1000000 | ./hoge2.sh > /dev/null
real 0m1.024s
user 0m1.516s
sys 0m0.024s
というように、ざっと30倍弱の差がついてしまいます。100万行というとデータ処理ではざらにある数字なので、この違いは無視できません。
readを使う場合
私の場合は、シェルスクリプトに対する標準入力を読む目的でreadを使ったことがありませんが、スクリプト中で次のような使い方をすることはあります。
ls file.* |
while read f ; do
mv ${f} ${f}.old
done
ただしこのように書くのも、せいぜいファイル数が100程度の場合で、それよりも多い場合はmanでいろいろ調べながらxargsなどで置き換えます。lsもechoに置き換えます。
まとめ!
ちょっと「~するべからず」調で書いてしまいましたが、以下のことをおさえておけばreadを使ってもかまわないでしょう。
標準入力の読み込みにreadを使うのは/dev/stdinからのリダイレクトに比べて高コスト。
おしまい。