sedを使ってbashシェルスクリプトを早くする。テキスト抜き出しなど。grepは遅い。

シェルスクリプティングでは様々なコマンドを組み合わせてスクリプトを書きますが、同じ結果を得るコマンドでも、コマンドの組み合わせによってその処理速度は大きく変わります

例えばあるストリングを取り出すためのコマンドについて考えてみましょう。

grepに h(ファイル名なし)とo(該当箇所のみ抜粋)のオプションをつければ簡単にマッチするストリングを取り出すことができますが、実はこれはあまり速い方法ではありません。

それよりもsedを使う方が処理速度としては断然速いです。

では例として、xmlタグの中から一つの要素を取り出そうとします。

<example color=”red” size=”5″>テスト</example>

という一行があり、この中からredを取り出すなら。

grepを使用する場合は

grep -Eo ‘color=”[^”]+”‘ | sed ‘s/^color=”//’ | sed ‘s/”$//’

たとえばこんなコマンドでgrepの-oオプションで該当箇所だけを取りだしてからsedでいらない部分を除くと、redがアウトプットとして取り出せますが、このgrepが入ったパターンだと処理速度は遅くなります。

代わりにストリングを取り出すだけで、形の決まったxmlであれば

sed ‘s/^.*color=”//’ | sed ‘s/”.*$//’

これだけで済みます。インプットの形によっては正規表現が必要となり面倒ですしgrepより感覚的ではありませんが、grepでマッチを探すより、前後を全てsedで取り除いてしまう方が速いです。

例えばこのような感じで同じインプットから同じredを取り出すコマンドを上記のgrepバーションとsedバージョンを1000繰り返すスクリプトであれば、

#!/bin/bash

input='<example color="red" size="5">test</example>'

START=$(date +%s.%N)
for i in {1..1000}; do
output=$(echo $input | grep -Eo 'color="[^"]+"' | sed 's/^color="//' | sed 's/"$//')
done
echo $output
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
echo $DIFF


START=$(date +%s.%N)
for i in {1..1000}; do
output=$(echo $input | sed 's/^.*color="//' | sed 's/".*$//')
done
echo $output
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
echo $DIFF

red
2.252697176
red
1.563371214

結果はsedのみの方が約1.5倍速くなります

とにかくsedは処理が速いコマンドなので、シェルスクリプトの中ではsedでできるものはなるべくsedに置き換えることがパフォーマンス向上に役立ちます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です