Bagaimana cara menjumlahkan waktu menggunakan bash?

12

Saya ingin mengetahui jumlah total waktu yang dibutuhkan oleh serangkaian proses di komputer saya untuk memutuskan apakah saya harus berjalan di sana atau di komputer yang lebih kuat. Jadi, saya memperkirakan waktu menjalankan setiap perintah. Outputnya terlihat seperti:

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

Bagaimana saya bisa menjumlahkan kolom kedua untuk mendapatkan total waktu berjalan? Saya bisa mencoba menelusuri setiap baris

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

tetapi ini tidak masuk akal karena nilainya bukan bilangan asli.

je_b
sumber

Jawaban:

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

Nizam Mohamed
sumber
Tampaknya sedikit hack-y, tapi hei, ini bekerja dengan cara yang menarik (semacam).
hjk
4

Dengan asumsi Anda menggunakan perintah builtin bash 'time', sebelum Anda menjalankan program, Anda bisa export TIMEFORMAT=%0R. Output kemudian akan ditambahkan dalam seluruh detik oleh awk. Informasi lebih lanjut tersedia di bagian 'Variabel Shell' pada halaman bash man.

Liczyrzepa
sumber
4

Jika Anda tidak dapat (atau tidak mau) menggunakan TIMEFORMAThanya perlu mentransfer waktu ke detik, kemudian tambahkan bersama. Misalnya keluaran pipa melalui:

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

Atau jika Anda ingin dapat bertukar echoperintah terakhir dengan

printf "%02d:%02d:%02d\n" $[sum/3600] $[sum/60] $[sum%60]
Costas
sumber
Notulen harus $[sum/60%60]mencabut jam kerja.
Jesse Chisholm
3

Memperbarui:

Berikut ini adalah implementasi baru yang memanfaatkan dc"basis output". Perhatikan bahwa jika jumlah total lebih dari 60 jam, ini akan menampilkan empat nilai yang dipisahkan oleh ruang alih-alih tiga. (Dan jika jumlah total kurang dari satu jam, hanya dua nilai yang dipisahkan ruang akan menjadi output.)

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

Input diasumsikan dalam tiga kali lipat jam, menit, detik, seperti yang ditunjukkan dalam pertanyaan.

Output pada input yang disediakan adalah:

 16 43

Jawaban asli:

Ayo lakukan ini dengan dcDesk Calculator Anda. Ini adalah back-end untuk bc, dan itu sangat fleksibel meskipun sering dianggap samar.


Pertama, beberapa pra-pemrosesan untuk memberikan waktu saja, dan mengubah titik dua menjadi spasi:

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

Kita juga bisa melakukan ini dengan Sed:

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

Saya akan pergi dengan Awk dan trkarena lebih sederhana. Salah satu dari perintah di atas menghasilkan output bersih dalam format berikut. (Saya menggunakan contoh teks saya sendiri karena saya menganggapnya lebih menarik; sudah termasuk jam. Anda akan bekerja juga.)

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

Diberikan waktu dalam format di atas, jalankan melalui script Sed berikut dan kirimkan hasilnya dcseperti yang ditunjukkan:

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

(Rusak untuk mengurangi pengguliran ke samping :)

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

Outputnya adalah detik, menit, jam, dalam urutan itu. (Perhatikan ini adalah urutan terbalik.) Saya baru belajar dcjadi ini bukan solusi yang sempurna, tapi saya pikir ini cukup bagus untuk dilihat pertama kali dc.

Contoh input dan output, disisipkan langsung dari terminal saya:

$ 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
$ 
Wildcard
sumber
2

Inilah solusi saya - gunakan split(). Mencetak total waktu dalam detik:

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

Mencetak dalam format waktu yang bagus:

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 juga mendukung strftime, tetapi ini akan menggunakan zona waktu Anda saat ini, sehingga hasilnya akan membingungkan.

myaut
sumber
Anda dapat menelepon gawkdengan TZ=UTC0 gawk...untuk menghapus masalah zona waktu.
Stéphane Chazelas
2

Pisahkan dan hitung saja:

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

Variasi pada tema di sini, tetapi lebih banyak pipa

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
sumber
0

Hampir semua shell dapat melakukan perhitungan:

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

Gunakan getseconds $=tdi zsh untuk membelahnya.

Ishak
sumber