Wie summiere ich die Zeit mit Bash?

12

Ich möchte wissen, wie viel Zeit eine Reihe von Prozessen in meinem Computer insgesamt benötigt, um zu entscheiden, ob ich dort oder auf einem stärkeren Computer ausgeführt werden soll. Also prognostiziere ich die Laufzeit jedes Befehls. Die Ausgabe sieht aus wie:

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

Wie kann ich die zweite Spalte summieren, um eine Gesamtlaufzeit zu erhalten? Ich könnte versuchen, jede Zeile durchzublättern

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

Dies macht jedoch keinen Sinn, da die Werte keine natürlichen Zahlen sind.

je_b
quelle

Antworten:

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" +%sergibt 0. So date -u -d "jan 1 1970 00:03:34" +%sergibt 214 Sekunden.

Nizam Mohamed
quelle
Scheint ein bisschen hackig zu sein, aber hey, es funktioniert auf interessante (Art) Weise.
hjk
4

Angenommen, Sie verwenden den integrierten Befehl bash 'time', bevor Sie Ihr Programm ausführen, können Sie dies export TIMEFORMAT=%0R. Die Ausgabe wird dann in ganzen Sekunden von awk hinzugefügt. Weitere Informationen finden Sie im Abschnitt 'Shell-Variablen' der Bash-Manpage.

Liczyrzepa
quelle
4

Wenn Sie TIMEFORMATIhre Zeit nicht in Sekunden umwandeln können (oder wollen) , addieren Sie sie. Zum Beispiel Rohrausgang durch:

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

Oder wenn Sie möchten, können Sie den letzten echoBefehl durch austauschen

printf "%02d:%02d:%02d\n" $[sum/3600] $[sum/60] $[sum%60]
Costas
quelle
Die Minuten sollten sein $[sum/60%60], um die Stunden abzustreifen.
Jesse Chisholm
3

Aktualisieren:

Hier ist eine neue Implementierung, die die dc"Ausgabebasis" nutzt . Beachten Sie, dass bei einer Gesamtsumme von mehr als 60 Stunden vier statt drei durch Leerzeichen getrennte Werte ausgegeben werden . (Und wenn die Gesamtsumme weniger als eine Stunde beträgt, werden nur zwei durch Leerzeichen getrennte Werte ausgegeben.)

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

Es wird angenommen, dass die Eingabe in Dreifachstunden, Minuten und Sekunden erfolgt, wie in der Frage gezeigt.

Die Ausgabe an der bereitgestellten Eingabe ist:

 16 43

Ursprüngliche Antwort:

Lassen Sie uns dies mit dcIhrem Schreibtischrechner tun . Es ist das Back-End bcund äußerst flexibel, obwohl es oft als kryptisch angesehen wird.


Zunächst einige Vorverarbeitungen, um nur die Zeiten anzugeben und die Doppelpunkte in Leerzeichen umzuwandeln:

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

Wir könnten das auch mit Sed machen:

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

Ich werde mit Awk gehen und trweil es einfacher ist. Jeder der obigen Befehle erzeugt eine saubere Ausgabe im folgenden Format. (Ich verwende meinen eigenen Beispieltext, weil ich ihn für interessanter halte. Er enthält Stunden. Ihre werden auch funktionieren.)

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

Führen Sie die angegebenen Zeiten im obigen Format durch das folgende Sed-Skript und leiten Sie das Ergebnis dcwie gezeigt weiter:

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

(Aufgeschlüsselt, um das seitliche Scrollen zu reduzieren :)

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

Die Ausgabe erfolgt in dieser Reihenfolge in Sekunden, Minuten, Stunden. (Beachten Sie, dass dies eine umgekehrte Reihenfolge ist.) Ich lerne gerade, dcdaher ist dies keine perfekte Lösung, aber ich denke, es ist ziemlich gut für einen ersten Blick dc.

Beispiel für eine Ein- und Ausgabe, die direkt von meinem Terminal eingefügt wurde:

$ 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
$ 
Platzhalter
quelle
2

Hier ist meine Lösung - verwenden split(). Gesamtzeit in Sekunden drucken:

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

Drucken im schönen Zeitformat:

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 unterstützt auch strftime, verwendet jedoch Ihre aktuelle Zeitzone, sodass die Ergebnisse verwirrend wären.

myaut
quelle
Sie können rufen Sie gawkmit TZ=UTC0 gawk...der Zeitzone Ausgabe zu entfernen.
Stéphane Chazelas
2

Einfach teilen und berechnen:

awk -F '[ :]' '
  {sum += $NF + 60 * ($(NF-1) + 60 * $(NF-2))}
  END {print sum}'
Stéphane Chazelas
quelle
0

Variation der Themen hier, aber mehr Pfeifen

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
Dr. Bombay
quelle
0

Fast jede Shell könnte rechnen:

#!/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"

Verwenden Sie getseconds $=tin zsh, um es zu teilen.

NotAnUnixNazi
quelle