¿Cómo sumar el tiempo usando bash?

12

Quiero saber la cantidad total de tiempo que una serie de procesos tomaría en mi computadora para decidir si debo ejecutarla allí o en una computadora más fuerte. Entonces, pronostico el tiempo de ejecución de cada comando. El resultado se ve así:

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

¿Cómo puedo sumar la segunda columna para obtener un tiempo total de ejecución? Podría intentar pasar cada línea

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

pero esto no tiene sentido ya que los valores no son números naturales.

je_b
fuente

Respuestas:

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

Nizam Mohamed
fuente
Parece un poco hack-y, pero bueno, funciona de una manera interesante (más o menos).
hjk
4

Suponiendo que está utilizando el comando incorporado bash 'time', antes de ejecutar su programa, puede hacerlo export TIMEFORMAT=%0R. La salida se agregará en segundos completos por awk. Hay más información disponible en la sección 'Variables de Shell' de la página de manual de bash.

Liczyrzepa
fuente
4

Si no puede (o no quiere) usar TIMEFORMATsu simple necesidad de transferir el tiempo en segundos, luego agréguelo. Por ejemplo, salida de tubería a través de:

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

O si lo desea, puede intercambiar el último echocomando por

printf "%02d:%02d:%02d\n" $[sum/3600] $[sum/60] $[sum%60]
Costas
fuente
Los minutos deben ser $[sum/60%60]para quitar las horas libres.
Jesse Chisholm
3

Actualizar:

Aquí hay una nueva implementación que hace uso de dcla "base de salida". Tenga en cuenta que si la suma total es más de 60 horas, esto generará cuatro valores separados por espacios en lugar de tres. (Y si la suma total es inferior a una hora, solo se generarán dos valores separados por espacios).

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

Se supone que la entrada está en triples de hora, minuto, segundo, como se muestra en la pregunta.

La salida en la entrada proporcionada es:

 16 43

Respuesta original:

Hagamos esto con dcsu calculadora de escritorio. Es el back-end bcy es extremadamente flexible, aunque a menudo se considera críptico.


Primero, algo de preprocesamiento para dar solo los tiempos y convertir los dos puntos en espacios:

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

También podríamos hacer esto con Sed:

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

Iré con Awk y trporque es más simple. Cualquiera de los comandos anteriores produce una salida limpia en el siguiente formato. (Estoy usando mi propio texto de ejemplo porque lo considero más interesante; tiene horas incluidas. El suyo también funcionará).

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

Dados los tiempos en el formato anterior, ejecútelos en el siguiente script Sed y canalice el resultado dccomo se muestra a continuación:

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

(Desglosado para reducir el desplazamiento lateral :)

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

La salida será segundos, minutos, horas, en esa secuencia. (Tenga en cuenta que esta es una secuencia inversa.) Estoy aprendiendo, dcasí que esta no es una solución perfecta, pero creo que es bastante buena para un primer vistazo dc.

Ejemplo de entrada y salida, pegado directamente desde mi terminal:

$ 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
$ 
Comodín
fuente
2

Aquí está mi solución: uso split(). Tiempo total de impresión en segundos:

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

Impresión en formato de hora agradable:

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 también admite strftime, pero usará su zona horaria actual, por lo que los resultados serían confusos.

myaut
fuente
Puede llamar gawkcon TZ=UTC0 gawk...para eliminar el problema de la zona horaria.
Stéphane Chazelas
2

Solo divide y calcula:

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

Variación sobre temas aquí, pero más tubos

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

Casi cualquier caparazón podría hacer los cálculos:

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

Use getseconds $=ten zsh para que se divida.

Isaac
fuente