Jak uruchomić czas na wielu poleceniach ORAZ zapisać wynik czasu do pliku?

65

Chcę uruchomić timepolecenie, aby zmierzyć czas kilku poleceń.

Chcę zrobić:

  • Zmierz czas działania wszystkich dodanych razem
  • Zapisz dane timewyjściowe do pliku
  • Napisz STDERRpolecenie, do którego zmierzamSTDERR

To, czego NIE chcę robić, to

  • Zapisz kilka poleceń w osobnym skrypcie (dlaczego? Ponieważ to wszystko jest już skryptem, który generuję programowo, a tworzenie INNEGO skryptu tymczasowego byłby bardziej bałagan niż chcę)

Co próbowałem do tej pory:

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

Nie działa, timedziała tylko na pierwszym.

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

Nie działa, (jest nieoczekiwany token.

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

Nie działa, „nie ma takiego pliku ani katalogu”.

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

Nie działa, „nie ma takiego pliku ani katalogu”.

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

Nie działa, ponieważ przekierowuje wszystko STDERRna outtime; Chcę tylko dane timewyjściowe.

I oczywiście,

time --output=outime echo "a";

Odtąd nie działa --output=outime: command not found.

Jak mogę to zrobić?

Karel Bílek
źródło

Odpowiedzi:

90

Użyj sh -c 'commands'jako polecenia, np .:

/usr/bin/time --output=outtime -p sh -c 'echo "a"; echo "b"'
Jim Paris
źródło
2
krótsza wersja:time -p sh -c 'echo "a"; echo "b"'
Geo
7

Spróbuj tego:

% (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

Wyjaśnienie:

Najpierw musimy znaleźć sposób na przekierowanie wyjścia time. Ponieważ timejest to wbudowana powłoka, do pomiaru mierzy się pełny wiersz poleceń, w tym przekierowania. A zatem,

% 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

[Uwaga: komentarz janos sugeruje, że tak nie jest bash.] Przekierowanie timewyjścia można osiągnąć, uruchamiając timepodpowłokę, a następnie przekierowując wyjście tej podpowłoki.

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

Teraz pomyślnie przekierowaliśmy dane wyjściowe time, ale jego dane wyjściowe są pomieszane z danymi wyjściowymi błędów komendy, którą mierzymy. Aby je rozdzielić, używamy dodatkowego deskryptora pliku.

Na „zewnątrz” mamy

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

Oznacza to: cokolwiek jest zapisane w deskryptorze pliku 3, zostanie wyprowadzone w to samo miejsce, w którym deskryptor pliku 2 (błąd standardowy) jest teraz wyprowadzany (terminal). A następnie przekierowujemy standardowy błąd do pliku timeout.

Teraz mamy: wszystko zapisane na stdout i fd 3 przejdzie do terminala, a wszystko zapisane na stderr przejdzie do pliku. Pozostało nam przekierowanie stderr mierzonego polecenia na fd 3.

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

Teraz, aby zmierzyć czas więcej niż jedną komendę, musimy uruchomić je w (innej!) Podpowłoce (w nawiasach). Aby przekierować wyjście błędów wszystkich na fd 3, musimy zgrupować je w nawiasach klamrowych.

Wreszcie dochodzimy do:

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

Otóż ​​to.

angus
źródło
Jest to błąd składniowy w powłoce POSIX. Prawdopodobnie bashism?
josch
@josch użyta tutaj powłoka to zsh.
angus
6

Nieprawidłowa odpowiedź, ale bardzo związana z pytaniem.
Wymagane są statystyki czasowe dla wielu programów połączone nawiasy. Oddziel polecenia średnikami.

time ( command1 ; command2 )
Martin T.
źródło
1
To jest miłe. Jeszcze lepiej, używaj && między poleceniami - tak time ( command1 && command2 ), aby w przypadku niepowodzenia pierwszego polecenia; nie przystąpi do wykonania drugiego.
bikashg