¿Cómo ejecutar el tiempo en múltiples comandos Y escribir la salida de tiempo en el archivo?

66

Quiero ejecutar el timecomando para medir el tiempo de varios comandos.

Lo que quiero hacer es:

  • Mida el tiempo de ejecución de todos ellos sumados
  • Escribir la timesalida en un archivo
  • Escriba el STDERRdel comando que estoy midiendoSTDERR

Lo que NO quiero hacer es

  • Escriba los varios comandos en un script separado (¿por qué? Porque todo esto ya es un script que estoy generando programáticamente, y crear OTRO script temporal sería más complicado de lo que quiero)

Lo que probé hasta ahora:

/usr/bin/time --output=outtime -p echo "a"; echo "b";

No funciona, timese ejecuta solo en el primero.

/usr/bin/time --output=outtime -p ( echo "a"; echo "b"; )

No funciona, (es una ficha inesperada.

/usr/bin/time --output=outtime -p { echo "a"; echo "b"; }

No funciona, "no existe tal archivo o directorio".

/usr/bin/time --output=outtime -p ' echo "a"; echo "b";'

No funciona, "no existe tal archivo o directorio".

time ( echo "a"; echo "b"; ) 2>outtime

No funciona, ya que redirige todo STDERRa outtime; Solo quiero la timesalida allí.

Y por supuesto,

time --output=outime echo "a";

No funciona desde entonces --output=outime: command not found.

¿Cómo puedo hacerlo?

Karel Bílek
fuente

Respuestas:

90

Usar sh -c 'commands'como comando, por ejemplo:

/usr/bin/time --output=outtime -p sh -c 'echo "a"; echo "b"'
Jim Paris
fuente
2
una versión más corta:time -p sh -c 'echo "a"; echo "b"'
Geo
8

Prueba esto:

% (time ( { echas z; echo 2 } 2>&3 ) ) 3>&2 2>timeoutput
zsh: command not found: echas
2
% cat timeoutput                                
( { echas z; echo 2; } 2>&3; )  0.00s user 0.00s system 0% cpu 0.004 total

Explicación:

Primero, tenemos que encontrar una manera de redirigir la salida de time. Dado que timees un shell integrado, toma la línea de comando completa como el comando a medir, incluidas las redirecciones. Así,

% time whatever 2>timeoutput
whatever 2> timeoutput  0.00s user 0.00s system 0% cpu 0.018 total
% cat timeoutput 
zsh: command not found: whatever

[Nota: el comentario de janos implica que este no es el caso bash.] Podemos lograr la redirección de timela salida de 's ejecutando timeen una subshell y luego redirigiendo la salida de esa subshell.

% (time whatever) 2> timeoutput
% cat timeoutput 
zsh: command not found: whatever
whatever  0.00s user 0.00s system 0% cpu 0.018 total

Ahora hemos redirigido con éxito la salida de time, pero su salida se mezcla con la salida de error del comando que estamos midiendo. Para separar los dos, usamos un descriptor de archivo adicional.

En el "exterior" tenemos

% (time ... ) 3>&2 2>timeout

Esto significa: lo que esté escrito en el descriptor de archivo 3, se enviará al mismo lugar que el descriptor de archivo 2 (error estándar) está emitiendo ahora (el terminal). Y luego redirigimos el error estándar al archivo timeout.

Así que ahora tenemos: todo lo escrito en stdout y fd 3 irá al terminal, y todo lo escrito en stderr irá al archivo. Lo que queda es redirigir el stderr del comando medido a fd 3.

% (time whatever 2>&3) 3>&2 2>timeout

Ahora, para que el tiempo mida más de un comando, debemos ejecutarlos en una (¡otra!) Subshell (dentro de paréntesis). Y para redirigir la salida de error de todos ellos a fd 3, necesitamos agruparlos dentro de llaves.

Entonces, finalmente, llegamos a:

% (time ( { whatever; ls } 2>&3 ) ) 3>&2 2>timeoutput

Eso es.

angus
fuente
Este es un error de sintaxis en un shell POSIX. ¿Probablemente un bashismo?
josch
@josch el shell utilizado aquí es zsh.
angus
6

No es la respuesta correcta pero está muy relacionada con la pregunta.
Obtener estadísticas de tiempo para múltiples programas se requieren paréntesis combinados. Comandos separados con punto y coma.

time ( command1 ; command2 )
Martin T.
fuente
1
Esto es bonito. Mejor aún, use && entre los comandos, de time ( command1 && command2 )modo que si el primer comando falla; no procederá a ejecutar al otro.
bikashg