Escriba la salida de `time` en un archivo, ¿por qué se necesitan paréntesis?

18

timeescribe en stderr, por lo que uno supondría que agregar 2>&1a la línea de comando debería enrutar su salida a stdout. Pero esto no funciona:

test@debian:~$ cat file 
one two three four
test@debian:~$ time wc file > wc.out 2>&1

real    0m0.022s
user    0m0.000s
sys     0m0.000s
test@debian:~$ cat wc.out 
 1  4 19 file

Solo con paréntesis funciona:

test@debian:~$ (time wc file) > wc.out 2>&1
test@debian:~$ cat wc.out 
 1  4 19 file

real    0m0.005s
user    0m0.000s
sys     0m0.000s

¿Por qué se necesitan paréntesis en este caso? ¿Por qué no se time wcinterpreta como un solo comando?

gatos lobo-revo
fuente
3
Tenga en cuenta que los resultados diferirán dependiendo de si timees la palabra clave de shell o /usr/bin/time. Puede haber varios conjuntos de descriptores involucrados aquí (el shell y los adjuntos a un timeproceso). Y no nos olvidemos de los implicados por la ()subshell. ( esperando un especialista en bash : p)
John WH Smith

Respuestas:

24

En ksh, bashy zsh, timeno es un comando (incorporado o no), es una palabra reservada en el idioma como forowhile .

Se usa para cronometrar una tubería 1 .

En:

time for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

Tiene una sintaxis especial que le dice al shell que ejecute esa tubería:

for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

E informe estadísticas de tiempo para ello.

En:

time cmd > output 2> error

Es lo mismo, estás temporización de lacmd > output 2> error comando y las estadísticas de cronometraje siguen en el stderr del shell.

Necesitas:

{ time cmd > output 2> error; } 2> timing-output

O:

exec 3>&2 2> timing-output
time cmd > output 2> error 3>&-
exec 2>&3 3>&-

Para que se redireccione stderr del shell timing-outputantes de que se use la construcción de tiempo (nuevamente, no comando ) (aquí de vez en cuandocmd > output 2> error 3>&- ).

También puede ejecutar esa timeconstrucción en una subshell que tiene su stderr redirigido:

(time cmd > output 2> error) 2> timing-output

Pero esa subshell no es necesaria aquí, solo necesita que se redireccione stderr en el momento en que time se invoca la construcción.

La mayoría de los sistemas también tienen un timecomando. Puede invocarlo deshabilitando la timepalabra clave. Todo lo que necesita hacer es citar esa palabra clave de alguna manera, ya que las palabras clave solo se reconocen como tales cuando son literales.

'time' cmd > output 2> error-and-timing-output

Pero cuidado, el formato puede ser diferente y el más antiguo de ambos timey cmdse fusionará error-and-timing-output.

Además, el timecomando, a diferencia deltime construcción, no puede cronometrar tuberías o comandos compuestos o funciones o funciones integradas de shell ...

Si se tratara de un comando incorporado, podría ser capaz de cronometrar invocaciones de funciones o incorporados, pero no podría cronometrar redireccionamientos o canalizaciones o comandos compuestos.


1 Tenga en cuenta que bashtiene (lo que se puede considerar como) un error por el cual time (cmd) 2> file(pero no time cmd | (cmd2) 2> filepor ejemplo) redirige la salida de temporización afile

Stéphane Chazelas
fuente
Bueno, a menudo insisto en mi cabeza para recordar que timees una palabra clave, no un shell incorporado.
Cuonglm
Gracias por el consejo sobre cómo usar 'time'para obtener el ejecutable, más útil que escribir /usr/bin/time(o incluso command time:-)).
alexis
@alexis también \time.
ctrl-alt-delor
7

No hay ningún comando con nombre time wc, timey wcse separan las palabras en shell.

Ahora, a menudo hay dos programas separados nombrados time, uno es una palabra clave de shell, otro es un comando externo . En shells, que timees una palabra clave de shell, cuando escribe time wc ..., el shell utiliza su palabra clave en timelugar de la utilidad de tiempo externo .

Cuando el shell utiliza la timepalabra clave, no necesita bifurcar () el nuevo proceso, el timeestándar actual y el error estándar no se modifican. La parte de redireccionamiento en:

time wc file > wc.out 2>&1

afecta wcsolo .

Cuando usa un comando compuesto(list) :

(time wc file) > wc.out 2>&1

el shell se ejecutó time wc filedentro de un subshell, (time wc file)se consideró un comando único y la parte de redirección afecta su salida estándar y error estándar, que ahora incluye ambos timey wc.


Puede hacer el mismo efecto, sin el costo de bifurcar un nuevo proceso utilizando otra forma de comando de agrupación {list;}:

{time wc file;} > wc.out 2>&1

Si usa externo time, entonces no enfrenta este problema, porque se ejecutó en un nuevo proceso:

/usr/bin/time wc file > wc.out 2>&1
Cuonglm
fuente
¿Hay alguna diferencia práctica entre usar timey /usr/bin/time? ¿Los ejecutables se llaman funcionalmente iguales?
Hashim el
2

Porque timeestás ejecutando es bash incorporado. Bash lo procesa de manera tan especial.

Si usará timebinario real , actuará exactamente de la manera que lo espera:

/usr/bin/time wc file > wc.out 2>&1

Aunque el resultado de este tiempo es un poco diferente:

 $ /usr/bin/time wc file > wc.out 
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata1900maxresident)k
0inputs+8outputs (0major+82minor)pagefaults 0swaps
prisa
fuente
99
Si fuera una construcción, no sería un problema. El problema es que es una palabra clave en el idioma. time cmd > outputveces el cmd > outputcomando y time foo | barveces foo | bar.
Stéphane Chazelas
1

No lo es time que escribe la información del tiempo. El builtin timehace que el shell escriba esto después de que se haya completado el comando. Pero la redirección afecta solo al comando.

En el (time ...)caso, la redirección se aplica a toda la subshell.

Hauke ​​Laging
fuente
0

Debido a que el tiempo es una cáscara incorporada, escribe en el stderr shell , en lugar del stderr del comando.

El uso de paréntesis fuerza el comando completo en un shell hijo cuyo stderr se puede redirigir.

El uso de corchetes produce un resultado similar sin realmente iniciar una subshell

  { time who ; } > /tmp/timwho >& /tmp/xx 

(sí, necesitas el punto y coma)

darkonc
fuente