はじめに
今回は、シェルスクリプトにおける「パフォーマンス」と「効率的な記述」に焦点を当てます。
大量のファイルを処理する場合や、頻繁に実行されるスクリプトにおいて、効率の差が大きな影響を与えることがあります。
ここでは、無駄なプロセス生成を避ける方法や、並列処理による高速化、そして実務で役立つワンライナーについて解説します。
1. 無駄なパイプとプロセス生成を避ける
シェルスクリプトの実行速度が遅くなる最大の要因の一つは、外部コマンドの呼び出しに伴うオーバーヘッドです。
特に、パイプ | でコマンドを繋ぐたびに新しいプロセスが生成されるため、不要なパイプは避けるべきです。
cat は本当に必要か?
ファイルの内容を grep や awk に渡す際、cat コマンドを使う必要はほとんどありません。
# 非効率:cat プロセスが無駄に起動する
cat access.log | grep "ERROR"
# 効率的:grep は直接ファイルを読み込める
grep "ERROR" access.log
ループ内での外部コマンド呼び出し
ループ処理の中で外部コマンドを繰り返し呼び出すと、パフォーマンスが著しく低下します。
# 非効率:1000回 date コマンドを起動する
for i in {1..1000}; do
date >> log.txt
done
# 効率的:ループ全体をリダイレクトし、date コマンドの呼び出し回数を減らす工夫をする
# (例:変数を使い回す、またはループ全体をリダイレクトしてI/Oを削減する)
now=$(date +%Y-%m-%d)
{
for i in {1..1000}; do
echo "$now - $i"
done
} > log.txt
2. xargs による並列処理
大量のファイルを処理する場合、一つずつ順番に実行するのではなく、xargs コマンドを使って並列に実行することで、高速化が可能です。
# 画像ファイルを変換する例(直列実行)
find . -name "*.jpg" | while read file; do convert "$file" "${file%.jpg}.png"; done
# 並列実行(-P オプションでプロセス数を指定)
# -P 4 で4並列で実行
find . -name "*.jpg" | xargs -P 4 -I {} convert "{}" "{}.png"
最近のCPUはマルチコアなので、並列処理を活用することで、リソースを有効利用できます。
3. 計測する time
パフォーマンス改善を行う際は、実際に計測を行うことが大事です。
time コマンド最も手軽です。
time ./script.sh
実行結果の real が実際にかかった時間、user と sys がCPU時間です。
並列処理を行うと real が短くなり、user + sys の合計は変わらない(あるいは増える)傾向にあります。
4. 実用的なワンライナー
ディレクトリ内のファイルサイズ合計を表示
du -sh .
特定の文字列を含むファイルを検索
grep -r "search_term" .
ログファイルから特定のIPアドレスのアクセス数を集計
# access.log の1列目がIPアドレスだと仮定
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -n 10
-
awkでIPアドレスのみ抽出 -
sortで並べ替え(uniqの前準備) -
uniq -cで重複カウント -
sort -nrでカウントの多い順に並べ替え -
head -n 10でトップ10を表示
まとめ
今回は、シェルスクリプトのパフォーマンスチューニングと、実務で役立つワンライナーについて解説しました。
無駄なプロセス生成を避けることや、xargs による並列処理を活用することで、スクリプトの実行速度を大幅に改善できます。
また、time コマンドによる計測を習慣づけることで、効果的なチューニングが可能になります。
これらのテクニックを活用して、より効率的なスクリプト作成に役立ててください。