Scrivi l'output di `time` in un file, perché sono necessarie le parentesi?


18

timescrive stderr, quindi si presume che l'aggiunta 2>&1alla riga di comando dovrebbe indirizzare il suo output a stdout. Ma questo non funziona:

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

Funziona solo con le parentesi:

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

Perché in questo caso sono necessarie le parentesi? Perché non viene time wcinterpretato come un singolo comando?


3
Si noti che i risultati differiranno a seconda che timesi tratti della parola chiave shell o /usr/bin/time. Potrebbero esserci diversi insiemi di descrittori coinvolti qui (la shell e quelli collegati a un timeprocesso). E non dimentichiamoci di quelli impliciti dalla ()subshell. (in attesa di uno specialista di bash : p)
John WH Smith

Risposte:


24

In ksh, bashe zsh, timenon è un comando (incorporato o no), è una parola riservata nella lingua come foro while.

È usato per cronometrare una pipeline 1 .

Nel:

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

Hai una sintassi speciale che dice alla shell di eseguire quella linea di pipe:

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

E segnala le statistiche di temporizzazione per questo.

Nel:

time cmd > output 2> error

E 'lo stesso, si sta temporizzazione il cmd > output 2> errorcomando e le statistiche di temporizzazione ancora andare avanti stderr della shell.

Hai bisogno:

{ 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>&-

Per reindirizzare lo stderr della shell timing-outputprima che venga usato il costrutto time (di nuovo, non command ) (qui al tempo cmd > output 2> error 3>&-).

Puoi anche eseguire quel timecostrutto in una subshell che ha il suo reindirizzamento standard:

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

Ma quella subshell non è necessaria qui, devi solo reindirizzare stderr nel momento in cui timeviene invocato il costrutto.

La maggior parte dei sistemi ha anche un timecomando. Puoi invocare quello disabilitando la timeparola chiave. Tutto quello che devi fare è citare quella parola chiave in qualche modo poiché le parole chiave sono riconosciute come tali solo se letterali.

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

Ma attenzione, il formato può essere diverso e lo standard di entrambi timee cmdverrà unito error-and-timing-output.

Inoltre, il timecomando, al contrario del timecostrutto, non può cronometrare pipeline o comandi composti o funzioni o builtin della shell ...

Se fosse un comando incorporato, potrebbe essere in grado di eseguire il cronometraggio di invocazioni di funzioni o builtin, ma non potrebbe cronometrare reindirizzamenti o pipeline o comandi composti.


1 Nota che bashha (quello che può essere considerato) un bug per cui time (cmd) 2> file(ma non time cmd | (cmd2) 2> fileper esempio) reindirizza l'output di temporizzazionefile


Bene, sottolineo spesso la mia testa per ricordare che timeè una parola chiave, non una shell incorporata.
cuonglm,

Grazie per il suggerimento sull'uso 'time'di ottenere l'eseguibile, più maneggevole della scrittura /usr/bin/time(o persino command time:-)).
alexis

@alexis also \time.
ctrl-alt-delor,

7

Non c'è nessun comando chiamato time wc, timee wcsono parole separate nella shell.

Ora, ci sono spesso due programmi separati denominati time, uno è la parola chiave shell, un altro è un comando esterno . Nelle shell che timeè una parola chiave della shell, durante la digitazione time wc ..., la shell ha usato la sua parola chiave timeanziché l' utilità di tempo esterna .

Quando la shell utilizza la timeparola chiave, non è necessario fork () nuovo processo, lo timestandard corrente e l'errore standard non vengono modificati. La parte di reindirizzamento in:

time wc file > wc.out 2>&1

colpisce wcsolo.

Quando si utilizza il comando composto(list) :

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

la shell veniva eseguita time wc fileall'interno di una subshell, (time wc file)era considerata un singolo comando e la parte di reindirizzamento influenza il suo output standard e l'errore standard, che ora include sia timee wc.


Puoi fare lo stesso effetto, senza il costo di creare un nuovo processo utilizzando un'altra forma di comando di raggruppamento {list;}:

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

Se usi l'esterno time, non hai questo problema, perché è stato eseguito con un nuovo processo:

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

C'è qualche differenza pratica tra l'utilizzo timee /usr/bin/time? Gli eseguibili chiamati sono funzionalmente uguali?
Hashim,

2

Perché timestai eseguendo è incorporato bash. Bash lo elabora in modo così speciale.

Se utilizzerai il vero timebinario, agirà esattamente come previsto:

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

Sebbene l'output di questo periodo sia leggermente diverso:

 $ /usr/bin/time wc file > wc.out 
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata1900maxresident)k
0inputs+8outputs (0major+82minor)pagefaults 0swaps

9
Se fosse un built-in, non sarebbe un problema. Il problema è che è una parola chiave nella lingua. time cmd > outputvolte il cmd > outputcomando e time foo | barvolte foo | bar.
Stéphane Chazelas,

1

Non è timeche scrive le informazioni sul tempo. Il comando incorporato timeconsente alla shell di scrivere questo dopo il completamento del comando. Ma il reindirizzamento influisce solo sul comando.

Nel (time ...)caso in cui il reindirizzamento venga applicato all'intera subshell.


0

Poiché il tempo è una shell incorporata, scrive sullo stderr della shell , piuttosto che sullo stderr del comando.

L'uso delle parentesi forza l'intero comando in una shell figlio il cui stderr può essere reindirizzato.

l'uso di parentesi graffe produce un risultato simile senza effettivamente avviare una sottostruttura

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

(sì, hai bisogno del punto e virgola)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.