nimsel
@nimsel (a a)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

シェルスクリプト(whileループ)の高速化

解決したいこと

シェルスクリプト(while)処理の高速化
10万行程度のYYYY-MM-DD HH:MM:SS形式の時刻を日本時間に変換する処理の実装をbusybox(ash環境)にて行っています。
現在テキストファイルに記載されている時刻をwhileループで読み込み、
シリアル値に変換を行い日本時間となるように調整し、あるべき時刻表示形式にdateコマンドを使って変換し、ファイル出力を行っているのですが、この処理が非常に時間がかかっているため、高速化できる方法がないか模索しているのですが、高速に変換処理を行う方法が見つけられませんでした。

発生している問題・エラー

whileループによる性能問題

現在以下のようなソースとなっており、どのように修正を行えば高速化できるかご教授いただきたいです。

該当するソースコード

UTC=32400
while read line
do
#シリアル値に変換
org_time = `date + %s -d "${line}"`
#日本時間に変換
japan_time=$(($org_time + $UTC))
#出力時間形式に変更
time = `date +"%Y-%m-%d %H:%M:%S" --date @$((japan_time))`
echo ${time} >> output.txt
done < input.txt
0

4Answer

日付の読み込みと日本時間への変換を一発で行えば2倍くらい早くなると思います。

while read line
do
time=`TZ=Asia/Tokyo date +"%Y-%m-%d %H:%M:%S" --date "${line}+00:00"`
echo ${time} >> output.txt
done < input.txt

それでもシェル内でのコマンドの実行は(echo のような組み込みコマンドを除けば)最低でも1回数ミリ秒かかるので、入力が数千行以上あれば焼け石に水です。適当なスクリプト言語で書き直すのがいいでしょう。

2Like

シェルスクリプトが遅くなる理由は、ループの中でサブシェルや外部コマンドを実行しているからです。つまり`...`の部分が遅くなっている原因です。

逆に言えばシェルの機能だけを使って日付の計算をすれば、速度を上げることができます。その方法は「シェルスクリプトでUNIX時間⇔日付の相互変換を行う関数(POSIX準拠)」で解説しています。

同等の処理を awk で実装する方法もありますが、やはりループの回数分 awk を呼び出してしまうと遅くなるため

awk '日付変換のコード' < input.txt

みたいにして、awk の中でループする必要があります。

1Like

awk with busybox

awkサンプルがあったので紹介します。
 cat input.txt | awk -f time.awk > output.txt

time.awk
#!/bin/awk -f 
//{
 utc = $0  
 gsub("[-T:+]", " ", utc)
 unixtime = mktime(utc) + ( 3600 * 9 )
 jst = strftime("%Y-%m-%d %H:%M:%S", unixtime)
 print(jst)
}
1Like

while 高速問題

 一括処理 または パイプで渡す案は どうでしょか?

while.sh
while read line ; do
    echo "${line}" 
done < inout.txt  >  output.txt   
cat input.txt | while2.sh
while read line ; do
    echo "${line}" 
done >  output.txt   

尚、 busybox なら awk で処理が楽です。

0Like

Your answer might help someone💌