Làm thế nào để tổng hợp thời gian sử dụng bash?


12

Tôi muốn biết tổng số thời gian mà một loạt các quy trình sẽ sử dụng trong máy tính của tôi để quyết định xem tôi nên chạy ở đó hay trong một máy tính mạnh hơn. Vì vậy, tôi dự báo thời gian chạy của mỗi lệnh. Đầu ra trông như sau:

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

Làm cách nào tôi có thể tính tổng cột thứ hai để có tổng thời gian chạy? Tôi có thể thử lướt qua từng dòng

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

nhưng điều này không có ý nghĩa vì các giá trị không phải là số tự nhiên.

Câu trả lời:


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" +%scho 0. Vì vậy, date -u -d "jan 1 1970 00:03:34" +%scho 214 giây.


Có vẻ như một chút hack-y, nhưng hey, nó hoạt động theo một cách thú vị (sắp xếp).
hjk

4

Giả sử bạn đang sử dụng lệnh dựng sẵn bash 'time', trước khi bạn chạy chương trình của mình, bạn có thể export TIMEFORMAT=%0R. Đầu ra sau đó sẽ trong toàn bộ giây có thể thêm bởi awk. Thông tin thêm có sẵn trong phần 'Biến Shell' trên trang bash man.


4

Nếu bạn không thể (hoặc không muốn), TIMEFORMATbạn chỉ cần chuyển thời gian thành giây, sau đó thêm nó lại với nhau. Ví dụ đầu ra đường ống thông qua:

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

Hoặc nếu bạn muốn có thể trao đổi cuối cùng echobằng cách

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

Các phút nên $[sum/60%60]để dải giờ nghỉ.
Jesse Chisholm

3

Cập nhật:

Đây là một triển khai mới sử dụng dc"cơ sở đầu ra". Lưu ý rằng nếu tổng tiền là hơn 60 giờ, điều này sẽ tạo ra bốn giá trị được phân tách bằng dấu cách thay vì ba. (Và nếu tổng tiền dưới một giờ, chỉ có hai giá trị được phân tách bằng dấu cách sẽ được xuất ra.)

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

Đầu vào được giả định là ba lần giờ, phút, giây, như trong câu hỏi.

Đầu ra trên đầu vào được cung cấp là:

 16 43

Câu trả lời gốc:

Hãy làm điều này với dcMáy tính bàn của bạn. Đó là back-end bcvà nó cực kỳ linh hoạt mặc dù thường được coi là khó hiểu.


Đầu tiên, một số tiền xử lý chỉ cung cấp thời gian và chuyển đổi dấu hai chấm thành khoảng trắng:

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

Chúng tôi cũng có thể làm điều này với Sed:

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

Tôi sẽ đi với Awk và trvì nó đơn giản hơn. Một trong hai lệnh trên tạo ra một đầu ra sạch theo định dạng sau. (Tôi đang sử dụng văn bản ví dụ của riêng mình vì tôi cho rằng nó thú vị hơn; bao gồm cả giờ. Bạn cũng sẽ làm việc.)

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

Thời gian đã cho ở định dạng trên, chạy chúng thông qua tập lệnh Sed sau đây và đưa kết quả vào dcnhư được hiển thị:

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

(Bị hỏng để giảm cuộn sang một bên :)

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

Đầu ra sẽ là giây, phút, giờ, theo trình tự đó. (Lưu ý đây là một chuỗi đảo ngược.) Tôi chỉ đang học dcnên đây không phải là một giải pháp hoàn hảo, nhưng tôi nghĩ nó khá tốt cho cái nhìn đầu tiên dc.

Ví dụ đầu vào và đầu ra, được dán trực tiếp từ thiết bị đầu cuối của tôi:

$ 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

Đây là giải pháp của tôi - sử dụng split(). Tổng thời gian in tính bằng giây:

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

In ở định dạng thời gian đẹp:

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 cũng hỗ trợ strftime, nhưng nó sẽ sử dụng múi giờ hiện tại của bạn, vì vậy kết quả sẽ gây nhầm lẫn.


Bạn có thể gọi gawkvới TZ=UTC0 gawk...để loại bỏ các vấn đề múi giờ.
Stéphane Chazelas

2

Chỉ cần chia và tính toán:

awk -F '[ :]' '
  {sum += $NF + 60 * ($(NF-1) + 60 * $(NF-2))}
  END {print sum}'

0

Sự thay đổi về các chủ đề ở đây, nhưng nhiều đường ống hơn

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

Hầu như bất kỳ shell nào cũng có thể làm toán:

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

Sử dụng getseconds $=ttrong zsh để có được nó để phân chia.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.