Chciałbym wyświetlić czas ukończenia skryptu.
Obecnie –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Pokazuje tylko czas rozpoczęcia i zakończenia skryptu. Czy byłby to można wyświetlić szczegółowe dane wyjściowe, takie jak czas procesora / czas io itp.?
Komentarze
- stackoverflow.com/questions/385408/ …
- Myślę, że obecna zaakceptowana odpowiedź nie jest wystarczająca ze względu na wahania czasowe.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Myślę, że proponowany przez Ciebie wątek nadal nie jest wystarczający, aby wyeliminować wpływ zdarzeń czasowych.
- Również powiązane: stackoverflow.com/questions/5152858/… lub nieco unix.stackexchange.com/questions/334145 / …
- Istnieje polecenie, które możesz uruchomić, a następnie automatycznie obliczyć wszystkie polecenia unixa, zapomniałeś jak włączyć?
Odpowiedź
Jus Nie używaj time
podczas wywoływania skryptu:
time yourscript.sh
Komentarze
- Wyprowadza trzy razy:
real
,user
isys
. Aby poznać ich znaczenie, zobacz tutaj . - i ” real to prawdopodobnie to, co ludzie chcą wiedzieć – ” Rzeczywiste to zegar ścienny – czas od początku do końca połączenia ”
- Czy istnieje sposób na przechwycenie standardowego wyjścia do pliku? Na przykład coś takiego jak
time $( ... ) >> out.txt
- Możesz to również zrobić z sekwencjami poleceń w wierszu poleceń, np .:
time (command1 && command2)
- Albo mógłby w swoim skrypcie po prostu zrobić: echo $ SECONDS zakładając, że to bash ….
Odpowiedź
Jeśli time
nie ma „opcji”,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Komentarze
- Pamiętaj, że działa to tylko wtedy, gdy ' nie potrzebujesz precyzji poniżej sekundy. W przypadku niektórych zastosowań może to być dopuszczalne , dla innych nie. Aby uzyskać nieco większą precyzję (' nadal wywołujesz
date
na przykład dwukrotnie, więc możesz na przykład w najlepiej w praktyce uzyskaj milisekundową precyzję, a prawdopodobnie mniej), spróbuj użyćdate +%s.%N
. (%N
to nanosekundy od całej sekundy .) - @ChrisH Oh. Dobrze to wskazać; interpretacja arytmetyczna basha jest tylko liczbami całkowitymi. Widzę dwa obvi wiele opcji; albo porzuć kropkę w ciągu formatu daty (i potraktuj wynikową wartość jako nanosekundy od epoki), więc użyj
date +%s%N
lub użyj czegoś bardziej wydajnego, takiego jakbc
aby obliczyć rzeczywisty czas działania na podstawie dwóch wartości, jak sugeruje jwchew. Mimo to uważam, że to podejście jest nieoptymalnym sposobem zrobienia tego;time
jest znacznie lepszy, jeśli jest dostępny, z powodów przedstawionych powyżej. - Po prostu zainstaluj
bc
, a następnie zrób to:runtime=$( echo "$end - $start" | bc -l )
- Jeśli wykonanie skryptu trwa kilka minut, użyj:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Dalej do @ rubo77 komentarz, jeśli twój skrypt trwa kilka godzin, użyj
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Odpowiedz
Po prostu wywołaj times
bez argumentów po zamknięciu skryptu.
Z ksh
lub zsh
, możesz też zamiast tego użyć time
. W przypadku zsh
time
oprócz użytkownika i poda również czas zegara ściennego system czas procesora.
Aby zachować stan zakończenia skryptu, możesz to zrobić:
ret=$?; times; exit "$ret"
Lub ty można również dodać pułapkę na EXIT
:
trap times EXIT
W ten sposób czasy będą wywoływane za każdym razem, gdy powłoka zakończy działanie i status wyjścia zostanie zachowany.
$ bash -c "trap times EXIT; : {1..1000000}" 0m0.932s 0m0.028s 0m0.000s 0m0.000s $ zsh -c "trap time EXIT; : {1..1000000}" shell 0.67s user 0.01s system 100% cpu 0.677 total children 0.00s user 0.00s system 0% cpu 0.677 total
Pamiętaj też, że wszystkie bash
, ksh
i zsh
mają $SECONDS
zmienną specjalną, która jest automatycznie zwiększana co sekundę. W obu zsh
i ksh93
, ta zmienna również może być zmiennoprzecinkowa (z typeset -F SECONDS
), aby uzyskać większą precyzję. To jest tylko czas zegara ściennego, a nie czas procesora.
Komentarze
- Ta zmienna $ SECONDS jest bardzo przydatna, dziękuję!
- Czy Twoje podejście eliminuje wpływ wydarzeń czasowych? – – Myślę, że Twoje podejście jest bliskie
time
podejściu przedstawionemu wcześniej.- – Myślę, że podejścietimeit
przedstawione w kodzie MATLAB może być tutaj przydatne. - Cześć, @St é phane Chazelas. Zauważyłem, że
times
nie ' nie podaje czasu na ścianie, prawda? na przykładbash -c 'trap times EXIT;sleep 2'
- @Binarus, tak, ta funkcja pochodzi z ksh. W przeciwieństwie do ksh93 / zsh, poza tym, że bash nie obsługuje zmiennoprzecinkowych, ' jest również uszkodzony przez to, że po ustawieniu SECONDS na 0, zmieni się na 1 z 0 na 1 sekundę później ( ponieważ uwzględnia tylko wynik
time()
, który ma tylko pełną, sekundową szczegółowość). - @Binarus, a nie ' s od 0 do 1. Jeśli ustawisz SECONDS na 0 o godzinie 12:00: 00.000, po jednej sekundzie zmieni się na 1. Ale jeśli ustawisz go na 12: 00: 00.999, zmieni się na 1 milisekundę później. Ale tak, zgadzam się, że prawdopodobnie nie ' nie ma większego znaczenia w praktyce, jeśli ' i tak nie ma precyzji poniżej sekundy.
Odpowiedź
Trochę się spóźniłem, ale chciałem opublikować swoje rozwiązanie (z dokładnością do sekundy ) na wypadek, gdyby ktoś natknął się na ten wątek podczas wyszukiwania. Dane wyjściowe są w formacie dni, godzin, minut i wreszcie sekund:
res1=$(date +%s.%N) # do stuff in here res2=$(date +%s.%N) dt=$(echo "$res2 - $res1" | bc) dd=$(echo "$dt/86400" | bc) dt2=$(echo "$dt-86400*$dd" | bc) dh=$(echo "$dt2/3600" | bc) dt3=$(echo "$dt2-3600*$dh" | bc) dm=$(echo "$dt3/60" | bc) ds=$(echo "$dt3-60*$dm" | bc) LC_NUMERIC=C printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds
Mam nadzieję, że ktoś tam jest to przydatne!
Komentarze
- Wydaje mi się, że nie ma innego (tylko bash) sposobu poza użyciem ' bc ', aby wykonać obliczenia. Przy okazji, naprawdę dobry skrypt;)
- Uważaj, FreeBSD ' s
date
nie obsługuje precyzji poniżej sekundy i po prostu doda literał „N
” do sygnatury czasowej. - Bardzo ładny skrypt, ale mój bash nie ' t obsłużyć drugą część. Dowiedziałem się również, że / 1 w bc skutecznie usuwa to, więc dodałem @ / 1 @ do obliczenia $ ds i wyświetla teraz bardzo ładnie!
- bc obsługuje modulo:
dt2=$(echo "$dt%86400" | bc)
. Po prostu mówię … Swoją drogą wolę formularzdt2=$(bc <<< "${dt}%86400")
, ale ' jest całkowicie osobisty. - Nie ' nie wiem jeszcze nic o
bc
, ale podział na86400
sprawia, że jestem nieufny wobec następujący powód: Są dni, które nie mają 86400 sekund, na przykład dni, w których czas jest przełączany z czasu letniego na normalny czas i odwrotnie, lub dni z sekundami przestępnymi. Jeśli takie dni stanowią część przedziału czasu, który chcesz obliczyć, tj. Znajdują się międzyres1
ares2
(łącznie z tymi wartościami), skrypt prawdopodobnie się nie powiedzie.
Odpowiedź
Moja metoda dla bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Komentarze
- Pokazuje upływ czasu, ale nie ' t pokaż ” drobnoziarniste dane wyjściowe, takie jak czas procesora, czas we / wy ” zgodnie z żądaniem w pytaniu.
- Osoby poszukujące odpowiedzi na zadane pytanie prawdopodobnie uznają to rozwiązanie za przydatne. Twój komentarz byłby lepiej zaadresowany do pytania OP.
Odpowiedź
Osobiście chciałbym podsumować wszystkie moje kod skryptu w jakiejś „głównej” funkcji, takiej jak ta:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Zwróć uwagę, jak łatwo jest użyć polecenia time
w tym scenariuszu. Oczywiście „nie mierzysz dokładnego czasu, w tym czasu analizy skryptu, ale uważam, że jest on wystarczająco dokładny w większości sytuacji.
Komentarze
- Świetne rozwiązanie, nie ' nie wymaga dodatkowych narzędzi i jest samodzielne.
Odpowiedź
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Tak, to wywołuje Pythona, ale jeśli możesz z tym żyć, to jest to całkiem fajne, zwięzłe rozwiązanie.
Komentarze
- Uważaj, że uruchomienie tego polecenia
python
w podpowłoce i odczytanie jego danych wyjściowych zajmie kilka milionów nanosekund w większości obecnych systemów. To samo przy uruchomieniudate
. - ” Kilka milionów nanosekund ” to kilka milisekund . Ludzi synchronizujących skrypty bash zwykle nie przejmują się tym zbytnio (chyba że uruchamiają kilka miliardów skryptów na megasekundę).
- Zauważ też, że nawet jeśli obliczenia są wykonywane w procesie Pythona, wartości zostały w całości zebrane przed wywołaniem Pythona. Czas wykonania skryptu zostanie zmierzony poprawnie, bez ” milionów nanosekund ” narzutu.
-
time main
powyżej jest o wiele bardziej przejrzysty …tak, możemy żyć z dużą degradacją, ale ' jest o wiele lepiej bez, więc niech ' zostanie inżynierami! -
$(echo $end - $start | bc)
zrobi to samo bez Pythona
Odpowiedź
To pytanie jest dość stare, ale próbując znaleźć mój ulubiony sposób zrobienia tego, ten wątek pojawił się wysoko … i jestem zaskoczony, że nikt o nim nie wspomniał:
perf stat -r 10 -B sleep 1
„perf” to narzędzie do analizy wydajności zawarte w jądrze pod „tools / perf” i często dostępne do zainstalowania jako oddzielny pakiet („perf” w CentOS i „linux-tools” w Debianie / Ubuntu). Linux Kernal perf Wiki zawiera znacznie więcej informacji na ten temat.
Uruchomienie „statystyki perf” daje sporo szczegółów, w tym średni czas wykonywania zaraz na końcu:
1.002248382 seconds time elapsed ( +- 0.01% )
Komentarze
- Co to jest
perf
? - @B Layer – edytowałem moją odpowiedź t podaj krótki opis ' perf '.
-
perf stat
teraz narzeka na ” Możesz nie mieć uprawnień do gromadzenia statystyk. „, chyba że uruchomisz niektóre polecenia zsudo
, co czyni go bezużytecznym we wszystkich scenariuszach, w których nie ' nie posiadasz całkowicie maszyny docelowej. - Niesamowite, dzięki! O wiele bardziej szczegółowe rozwiązanie niż sugerują
time
inni. W szczególnościtime
nie ma zastosowania do pomiaru rozwiązań konkurencji kodu (tak jak nie ' t czasu drukowania w milisekundach i mniej) , podczas gdy Twoje rozwiązanie tak.
Odpowiedź
Mała funkcja powłoki, którą można dodać przed polecenia do mierzenia ich czasu:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Następnie użyj go w swoim skrypcie lub w wierszu poleceń w następujący sposób:
tm the_original_command with all its parameters
Komentarze
- Warto byłoby dodać milisekundy, próbowano ilke
s=$(date +%s000)
, nie jestem pewien jeśli to zadziała. - @loretoparisi przez milisekundy, możesz spróbować
date +%s%N
. Zobacz serverfault.com/questions/151109/… - To jest świetne, ale bezpieczniejsze użyj
"$@"
Odpowiedz
#!/bin/csh #PBS -q glean #PBS -l nodes=1:ppn=1 #PBS -l walltime=10:00:00 #PBS -o a.log #PBS -e a.err #PBS -V #PBS -M [email protected] #PBS -m abe #PBS -A k4zhang-group START=$(date +%s) for i in {1..1000000} do echo 1 done END=$(date +%s) DIFF=$(echo "$END - $START" | bc) echo "It takes DIFF=$DIFF seconds to complete this task..."
Komentarze
- Czym to się naprawdę różni od innych już udzielonych odpowiedzi, w których zastosowano
date
przed i po skrypt i wypisuje różnicę między nimi?
Odpowiedź
-
Po prostu użyj
time [any command]
. Na przykład:time sleep 1
będzie spać w czasie rzeczywistym (tj. Według czasu stopera) od ~ 1.000 do ~ 1.020 s, jak pokazano tutaj:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Cóż za piękna rzecz. Możesz umieścić po nim dowolne polecenie, a wynik zostanie wyświetlony w ładnej, czytelnej dla człowieka formie. Naprawdę lubię używać go do kompilacji czasu. Np .:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… lub dla operacji git, które potencjalnie mogą być naprawdę długi, więc mogę rozwinąć realistyczne oczekiwania mentalne:
# time how long it takes to pull from a massive repo when # I"m working from home during COVID-19. NB: `git pull` # is sooooo much slower than just pulling the one branch # you need with `git pull origin <branch>`, so just fetch # or pull what you need! time git pull origin master
-
Dla bardziej dostosowanych potrzeb czasowych , gdzie może być konieczne zmodyfikowanie wyniku lub przekonwertowanie go na inne formy w bash użyj wewnętrznej zmiennej
$SECONDS
. Oto „demo, w tym konwersja tych sekund na inne jednostki, takie jak minuty zmiennoprzecinkowe:Zwróć uwagę, że
dt_min
jest zaokrąglane z0.01666666666...
(1 sekunda = tyle minut) do0.017
w tym przypadku, ponieważ używam funkcjiprintf
do zaokrąglania. Poniższasleep 1;
część jest miejscem, w którym „wezwałbyś swój skrypt do uruchomienia i czasu, ale ja” zamiast tego śpię tylko przez 1 sekundę ze względu na to demo.Polecenie:
start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); \ dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); \ echo "dt_sec = $dt_sec; dt_min = $dt_min"
Wynik:
dt_sec = 1; dt_min = 0.017
Powiązane:
- Czytaj więcej około
bc
iprintf
w mojej odpowiedzi tutaj: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Nie pamiętam już, gdzie po raz pierwszy dowiedziałem się o poleceniu
time
, ale mogło to pochodzić z @Trudbert „jest tutaj odpowiedzią .
Odpowiedź
Używając tylko bash można również zmierzyć i obliczyć czas trwania części skryptu powłoki (lub czas, jaki upłynął dla całego skryptu):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
możesz teraz wydrukować różnicę:
echo "duration: $((end-start)) seconds."
jeśli potrzebujesz tylko przyrostowego czasu trwania, wykonaj:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Czas trwania możesz również zapisać w zmiennej:
let diff=end-start
Komentarze
- ^ TO jest odpowiedź dla ludzi. Lub prościej: na koniec $ SECONDS. Jest to ' zmienna typu BUILT-IN Bash. Wszystkie inne odpowiedzi wymagają tylko dodatkowej pracy, aby ponownie wymyślić to koło …
- To tylko powtórzenie wcześniejszej odpowiedzi Marksa unix.stackexchange .com / a / 340156/155362 .
Odpowiedź
Funkcja pomiaru czasu oparta na SECONDS
, ograniczone tylko do szczegółowości drugiego poziomu, nie używa żadnych poleceń zewnętrznych:
time_it() { local start=$SECONDS ts ec printf -v ts "%(%Y-%m-%d_%H:%M:%S)T" -1 printf "%s\n" "$ts Starting $*" "$@"; ec=$? printf -v ts "%(%Y-%m-%d_%H:%M:%S)T" -1 printf "%s\n" "$ts Finished $*; elapsed = $((SECONDS-start)) seconds" # make sure to return the exit code of the command so that the caller can use it return "$ec" }
Na przykład:
time_it sleep 5
daje
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Odpowiedź
Czy używać wbudowanego czasu bash?
time: time [-p] PIPELINE Execute PIPELINE and print a summary of the real time, user CPU time, and system CPU time spent executing PIPELINE when it terminates. The return status is the return status of PIPELINE. The `-p" option prints the timing summary in a slightly different format. This uses the value of the TIMEFORMAT variable as the output format.
Przykład:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Wynik:
The command took 0.108s
Odpowiedź
Oto odmiana Alexa ”odpowiedź. Zależy mi tylko na minutach i sekundach, ale chciałem też mieć inny format. Zrobiłem więc tak:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Komentarze
- Dlaczego głos przeciw? Czy mam błąd?
- Używanie
python
do tego obliczenia też wygląda na błąd, przepraszam. Dlaczego ludzie mogą ' po prostu zadzwonić pod numertime
jest poza mną.
Odpowiedź
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Odpowiedź
Zaakceptowane rozwiązanie przy użyciu time
zapisuje do stderr
.
Rozwiązanie korzystające z times
zapisuje do stdout
.
Rozwiązania używające $SECONDS
nie mają dokładności poniżej sekundy.
Inne rozwiązania obejmują wywoływanie programów zewnętrznych, takich jak date
lub perf
, co nie jest wydajne.
Jeśli jesteś w porządku z którymkolwiek z nich, użyj go.
Ale jeśli potrzebujesz wydajnego rozwiązania , aby uzyskać czasy z dokładnością do milisekund i potrzebujemy ich w zmiennych takich, że oryginalne wyjście pozostaje niezakłócone możesz łączyć podstawianie procesu z niektórymi przekierowaniami wokół time
, co jest znacznie szybsze niż wywołanie zewnętrznych programów i zezwala na przekierowania wokół skryptu opakowującego taktowanie, jak w oryginalnym poleceniu / skrypcie.
# Preparations: Cmd=vgs # example of a program to be timed which is writing to stdout and stderr Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }" # other example; replace with your own TIMEFORMAT="%3R %3U %3S" # make time output easy to parse
Wybierz jeden z następujących wariantów analizowania danych wyjściowych time
odpowiedni do Twoich potrzeb:
Najkrótszy wariant, w którym stdout
z $Cmd
jest zapisany w stderr
i nic do stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Dłuższy wariant, który zachowuje oryginalne stdout
i stderr
oddzielone od siebie:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Najbardziej skomplikowany wariant obejmuje zamknięcie dodatkowych deskryptorów plików w taki sposób, że $Cmd
jest wywoływane tak, jakby nie było otaczającego go otoki czasowej i , takie jak vgs
, nie narzekają na wyciekły deskryptory plików:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Ty może nawet sfałszować dodawanie zmiennoprzecinkowe w bash
bez wywoływania bc
, co byłoby znacznie wolniejsze:
CPU=`printf %04d $((10#${User/.}+10#${System/.}))` # replace with your own postprocessing echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2 # redirected independent of $Cmd
Możliwe wyniki z dwoma przykładami $Cmd
na wolnym procesorze:
File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash VG #PV #LV #SN Attr VSize VFree b3 3 24 0 wz--n- 1.31t 1.19t CPU 0.052 s, Elapsed 0.056 s
Lub:
stdout stderr CPU 0.008 s, Elapsed 0.109 s