Voglio time
un comando che consiste in due comandi separati con un output di piping a un altro. Ad esempio, considera i due script seguenti:
$ cat foo.sh
#!/bin/sh
sleep 4
$ cat bar.sh
#!/bin/sh
sleep 2
Ora, come posso time
comunicare il tempo impiegato foo.sh | bar.sh
(e sì, so che la pipa non ha senso qui, ma questo è solo un esempio)? Funziona come previsto se li eseguo in sequenza in una subshell senza piping:
$ time ( foo.sh; bar.sh )
real 0m6.020s
user 0m0.010s
sys 0m0.003s
Ma non riesco a farlo funzionare durante il piping:
$ time ( foo.sh | bar.sh )
real 0m4.009s
user 0m0.007s
sys 0m0.003s
$ time ( { foo.sh | bar.sh; } )
real 0m4.008s
user 0m0.007s
sys 0m0.000s
$ time sh -c "foo.sh | bar.sh "
real 0m4.006s
user 0m0.000s
sys 0m0.000s
Ho letto una domanda simile ( Come eseguire il tempo su più comandi E scrivere l'output del tempo su file? ) E ho anche provato l' time
eseguibile standalone :
$ /usr/bin/time -p sh -c "foo.sh | bar.sh"
real 4.01
user 0.00
sys 0.00
Non funziona nemmeno se creo un terzo script che esegue solo la pipe:
$ cat baz.sh
#!/bin/sh
foo.sh | bar.sh
E poi il tempo che:
$ time baz.sh
real 0m4.009s
user 0m0.003s
sys 0m0.000s
È interessante notare che non sembra che time
esca non appena viene eseguito il primo comando. Se cambio bar.sh
a:
#!/bin/sh
sleep 2
seq 1 5
E poi time
, mi aspettavo che l' time
output venisse stampato prima del seq
ma non lo è:
$ time ( { foo.sh | bar.sh; } )
1
2
3
4
5
real 0m4.005s
user 0m0.003s
sys 0m0.000s
Sembra time
che non conti il tempo impiegato per l'esecuzione bar.sh
nonostante l'attesa che finisca prima di stampare il suo rapporto 1 .
Tutti i test sono stati eseguiti su un sistema Arch e usando bash 4.4.12 (1)-release. Posso usare solo bash per il progetto di cui fa parte, quindi anche se zsh
o qualche altra shell potente può aggirarlo, non sarà una soluzione praticabile per me.
Quindi, come posso ottenere il tempo necessario per l'esecuzione di una serie di comandi inoltrati? E, mentre ci siamo, perché non funziona? Sembra che time
esca immediatamente non appena il primo comando è terminato. Perché?
So di poter ottenere i singoli tempi con qualcosa del genere:
( time foo.sh ) 2>foo.time | ( time bar.sh ) 2> bar.time
Ma vorrei ancora sapere se è possibile programmare l'intera operazione come un'unica operazione.
1 Questo non sembra essere un problema di buffer, ho provato a fare funzionare gli script con unbuffered
e stdbuf -i0 -o0 -e0
ed i numeri erano ancora stampati prima della time
uscita.