bashを使用して時間を合計する方法は?


12

一連のプロセスがコンピューターで実行する必要がある合計時間を知りたいのですが、そこで実行するか、より強力なコンピューターで実行するかを決定します。それで、各コマンドの実行時間を予測しています。出力は次のようになります。

process1    00:03:34
process2    00:00:35
process3    00:12:34

2番目の列を合計して合計実行時間を取得するにはどうすればよいですか?各行をピップしてみることができます

awk '{sum += $2 } END { print sum }

しかし、値は自然数ではないため、これは意味がありません。

回答:


15
#!/bin/sh

EPOCH='jan 1 1970'
sum=0

for i in 00:03:34 00:00:35 00:12:34
do
  sum="$(date -u -d "$EPOCH $i" +%s) + $sum"
done
echo $sum|bc

date -u -d "jan 1 1970" +%s0 date -u -d "jan 1 1970 00:03:34" +%sを与えます。つまり、214秒を与えます。


少しハックのように見えますが、ちょっと、興味深い(一種の)方法で動作します。
hjk 2015年

4

bash 'time'組み込みコマンドを使用していると仮定すると、プログラムを実行する前に、次のことができexport TIMEFORMAT=%0Rます。出力は、awkによって秒単位で追加可能になります。詳細については、bashのmanページの「シェル変数」セクションを参照してください。


4

TIMEFORMAT時間を秒単位で転送する必要があるだけでは使用できない(または使用したくない)場合は、合計します。たとえば、出力をパイプします。

{                                           
sum=0
while IFS="[ :]" proc_name h m s
do
    let sum+=$((60*($m+60*$h)+$s)) 
done 
echo $sum  
} 

または、最後のecho-command を交換したい場合

printf "%02d:%02d:%02d\n" $[sum/3600] $[sum/60] $[sum%60]

分は$[sum/60%60]時間を取り除くためのものです。
ジェシーチザム

3

更新:

dcの「出力ベース」を利用する新しい実装を次に示します。合計が60時間を超える場合、3つではなく4つのスペースで区切られた値が出力されることに注意してください。(合計が1時間未満の場合、スペースで区切られた2つの値のみが出力されます。)

awk '{print $2}' file.txt | tr : \ | dc -f - -e '60o0ddd[+r60*+r60d**+z1<a]dsaxp'

質問に示されているように、入力は時間、分、秒の3つであると想定されます。

指定された入力の出力は次のとおりです。

 16 43

元の答え:

dc電卓でこれをやってみましょう。これはのバックエンドでありbc、非常に柔軟性がありますが、不可解と見なされることがよくあります。


最初に、時間のみを指定し、コロンをスペースに変換するためのいくつかの前処理:

awk '{print $2}' | tr : ' '

Sedでもこれを行うことができます。

sed -En -e 's/^.*([0-9][0-9]):([0-9][0-9]):([0-9][0-9]).*$/\1 \2 \3/p'

私はAwkを使いますが、trそれはより簡単だからです。上記のコマンドはどちらも、次の形式でクリーンな出力を生成します。(私はそれがより興味深いと思うので、私は自分の例のテキストを使用しています。それは時間も含まれています。あなたのテキストも同様に機能します。)

$ cat input
9 39 42
8 04 50
7 49 32
10 01 54
7 19 18

上記の形式の時間を指定して、次のSedスクリプトを実行し、結果を次のようにパイプdcします。

sed -e '1s/^/0 /' -e 's/$/ r 60 * + r 60 60 * * + +/' -e '$s/$/ 60 60 * ~ 60 ~ f/' input | dc

(横スクロールを減らすために分割されました:)

sed <input \
    -e '1s/^/0 /' \
    -e 's/$/ r 60 * + r 60 60 * * + +/' \
    -e '$s/$/ 60 60 * ~ 60 ~ f/' |
      dc 

出力は、その順序で秒、分、時間になります。(これは逆のシーケンスであることに注意してください。) 私はただ学習しdcているだけなので、これは完全な解決策ではありませんが、を最初に見るのにはかなり良いと思いますdc

端末から直接貼り付けた入力と出力の例:

$ cat input 
9 39 42
8 04 50
7 49 32
10 01 54
7 19 18
$ sed -e '1s/^/0 /' -e 's/$/ r 60 * + r 60 60 * * + +/' -e '$s/$/ 60 60 * ~ 60 ~ f/' input | dc 
16
55
42
$ 

2

これが私の解決策です-使用split()。秒単位での合計時間の印刷:

awk '{
        split($2, tm, ":");
        tottm += tm[3] + tm[2] * 60 + tm[1] * 3600;
    }
    END {
        print tottm;
    }' ptime

素敵な時間形式での印刷:

awk '{
        split($2, tm, ":");
        secs += tm[3]; 
        mins += tm[2] + int(secs / 60); 
        hrs += tm[1] + int(mins / 60);
        secs %= 60; mins %= 60;
    }
    END {
        printf "%d:%d:%d\n", hrs, mins, secs;
    }' ptime

GNU awkはstrftimeもサポートしますが、現在のタイムゾーンを使用するため、結果がわかりにくくなります。


で電話gawkTZ=UTC0 gawk...かけて、タイムゾーンの問題を削除できます。
ステファンChazelas


0

ここでのテーマのバリエーションですが、より多くのパイプ

echo """
process1    00:03:34
process2    00:00:35
process3    00:12:34
"""  | \
     sed 's/process.  *\([0-9]\)/\1/g' | \
     xargs -i{} date +%s --date "1970-1-1 {}" | \
     awk '{sum += $1; cnt +=1} 
         END {
               print sum / 60, " total minutes processing";
               print (sum / 3600) / cnt, "minutes per job"
         }'
916.717  total minutes processing
5.09287 minutes per job

0

ほとんどすべてのシェルで計算できます。

#!/bin/sh

IFS=:; set +f
getseconds(){ echo "$(( ($1*60+$2)*60+$3 ))"; }

for   t in 00:03:34 00:00:35 00:12:34
do    sum=$((sum + $(getseconds $t) ))
done
printf '%s\n' "$sum"

getseconds $=tzshで使用して分割します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.