如何使用bash求和时间?


12

我想知道一系列过程将花费在我的计算机上的总时间,以确定我应该在那运行还是在功能更强大的计算机上运行。因此,我正在预测每个命令的运行时间。输出如下:

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

如何汇总第二列以获得总运行时间?我可以尝试通过每行

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

但这是没有意义的,因为这些值不是自然数。

Answers:


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" +%s给出0。因此date -u -d "jan 1 1970 00:03:34" +%s给出214秒。


的确有点骇人听闻,但嘿,它以一种有趣的(多种)方式起作用。
hjk 2015年

4

假设您正在使用bash的“ time”内置命令,则可以在运行程序之前进行操作export TIMEFORMAT=%0R。然后,输出将在整秒内由awk可加。bash手册页的“ Shell变量”部分提供了更多信息。


4

如果您不能(或不想)使用TIMEFORMAT您的仅需将时间转换为秒,则将其加在一起。例如,通过以下管道输出:

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

或者,如果您可以交换last echo-command by

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

分钟应该是$[sum/60%60]减少时间。
杰西·奇斯霍尔姆

3

更新:

这是一个利用dc的“输出基础” 的新实现。请注意,如果总和超过60小时,则将输出四个以空格分隔的值,而不是三个。(如果总和少于一小时,将仅输出两个以空格分隔的值。)

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

如问题所示,假定输入是小时,分钟,秒的三倍。

提供的输入上的输出为:

 16 43

原始答案:

让我们使用dc您的Desk Calculator来做到这一点。它是的后端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

2

只需拆分并计算:

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

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

几乎所有的shell都可以进行数学计算:

#!/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 $=t在zsh中使用以使其拆分。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.