Z drugiej strony, czy nie możesz użyć timepolecenia?
anishsane,
Zamiast tego użyj czasu uniksowego date +%s, a następnie odejmij, aby uzyskać różnicę w sekundach.
roblogic 21.04.17
Odpowiedzi:
476
Bash ma przydatną SECONDSwbudowaną zmienną, która śledzi liczbę sekund, które upłynęły od uruchomienia powłoki. Ta zmienna zachowuje swoje właściwości po przypisaniu, a wartość zwracana po przypisaniu jest liczbą sekund od przypisania plus przypisana wartość.
Dlatego możesz po prostu ustawić SECONDS0 przed rozpoczęciem zdarzenia czasowego, po prostu przeczytać SECONDSpo zdarzeniu i wykonać arytmetykę czasu przed wyświetleniem.
SECONDS=0# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."
Ponieważ to rozwiązanie nie zależy od date +%s(które jest rozszerzeniem GNU), jest przenośne dla wszystkich systemów obsługiwanych przez Bash.
+1. Nawiasem mówiąc, możesz oszukać datew wykonaniu arytmetyki czasu, pisząc date -u -d @"$diff" +'%-Mm %-Ss'. (To interpretuje $diffjako sekundę od epoki i oblicza minuty i sekundy w UTC). Prawdopodobnie nie jest to już bardziej eleganckie, po prostu lepiej zaciemnione. :-P
ruakh
13
Ładne i proste. Jeśli ktoś potrzebuje godzin:echo "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
chus
6
Należy przeczytać, $(date -u +%s)aby zapobiec wyścigowi w dniach, w których zmienia się czas letni. I strzeżcie się złych sekund przestępnych;)
Tino
3
@ daniel-kamil-kozar Nice find. Jest to jednak trochę kruche. Jest tylko jedna taka zmienna, więc nie można jej używać rekurencyjnie do mierzenia wydajności, a nawet gorzej po unset SECONDSjej zniknięciu:echo $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
Tino,
6
@ParthianShot: Przykro mi, że tak uważasz. Uważam jednak, że ta odpowiedź jest najbardziej potrzebna podczas wyszukiwania odpowiedzi na pytanie takie jak to: mierzyć czas między zdarzeniami, a nie obliczać czas.
Daniel Kamil Kozar
99
sekundy
Do pomiaru upływu czasu (w sekundach) potrzebujemy:
liczba całkowita reprezentująca liczbę upływających sekund i
sposób na konwersję takiej liczby całkowitej na użyteczny format.
Liczba całkowita upływających sekund:
Istnieją dwa wewnętrzne sposoby na znalezienie wartości całkowitej dla liczby upływających sekund:
Zmienna Bash SECONDS (jeśli nie ustawiono SECONDS, traci swoją specjalną właściwość).
Ustawienie wartości SECONDS na 0:
SECONDS=0
sleep 1# Process to execute
elapsedseconds=$SECONDS
Przechowywanie wartości zmiennej SECONDSna początku:
a=$SECONDS
sleep 1# Process to execute
elapsedseconds=$(( SECONDS - a ))
Opcja Bash printf %(datefmt)T:
a="$(TZ=UTC0 printf '%(%s)T\n' '-1')"### `-1` is the current time
sleep 1### Process to execute
elapsedseconds=$(( $(TZ=UTC0 printf '%(%s)T\n''-1')- a ))
Konwertuj taką liczbę całkowitą na użyteczny format
Bash wewnętrzny printfmoże to zrobić bezpośrednio:
%(FORMAT)Twyświetla ciąg daty i godziny wynikający z użycia FORMATU jako ciągu formatu dla strftime(3). Powiązany argument to liczba sekund od Epoki lub -1 (bieżący czas) lub -2 (czas uruchamiania powłoki). Jeśli nie podano odpowiedniego argumentu, domyślnie jest używany bieżący czas.
Możesz więc zadzwonić, textifyDuration $elpasedsecondsgdzie textifyDurationjest jeszcze jedna implementacja drukowania czasu trwania:
Aby uzyskać sformatowany czas, powinniśmy skorzystać z zewnętrznego narzędzia (data GNU) na kilka sposobów, aby osiągnąć długość prawie roku, w tym nanosekundy.
Matematyka w dacie.
Nie ma potrzeby stosowania zewnętrznej arytmetyki, zrób to wszystko w jednym kroku date:
date -u -d "0 $FinalDate seconds - $StartDate seconds"+"%H:%M:%S"
Tak, 0w wierszu polecenia jest zero. To jest potrzebne.
Zakłada się, że możesz zmienić date +"%T"polecenie na date +"%s"polecenie, aby wartości zostały zapisane (wydrukowane) w kilka sekund.
Pamiętaj, że polecenie jest ograniczone do:
Wartości dodatnie $StartDatei $FinalDatesekundy.
Wartość w $FinalDatejest większa (później) niż $StartDate.
Różnica czasu mniejsza niż 24 godziny.
Akceptujesz format wyjściowy z godzinami, minutami i sekundami. Bardzo łatwa do zmiany.
Dopuszczalne jest użycie czasów -u UTC. Aby uniknąć „DST” i korekt czasu lokalnego.
Jeśli musisz użyć 10:33:56ciągu, cóż, po prostu przekonwertuj go na sekundy,
również słowo sekundy może być skrócone jako sec:
Jeśli wymagane jest obliczenie dłuższych (do 364 dni) różnic czasowych, musimy użyć początku (jakiegoś) roku jako wartości odniesienia i wartości formatu %j(numeru dnia w roku):
Podobny do:
string1="+10 days 10:33:56.5400022"
string2="+35 days 10:36:10.8800056"StartDate=$(date -u -d "2000/1/1 $string1"+"%s.%N")FinalDate=$(date -u -d "2000/1/1 $string2"+"%s.%N")
date -u -d "2000/1/1 $FinalDate sec - $StartDate sec"+"%j days %H:%M:%S.%N"Output:026 days 00:02:14.340003400
Niestety, w tym przypadku musimy ręcznie odjąć 1JEDEN od liczby dni. Polecenie daty wyświetla pierwszy dzień roku jako 1. Nie jest to trudne ...
Narzędzie używane w mniejszych urządzeniach (bardzo mały plik wykonywalny do zainstalowania): Busybox.
Utwórz link do busyboksa o nazwie data:
$ ln -s /bin/busybox date
Użyj go następnie, wywołując to date(umieść w katalogu zawierającym ŚCIEŻKĘ).
Lub stwórz alias:
$ alias date='busybox date'
Data Busybox ma fajną opcję: -D, aby otrzymać format godziny wejściowej. Otwiera to wiele formatów, które można wykorzystać jako czas. Za pomocą opcji -D możemy bezpośrednio przekonwertować czas 10:33:56:
date -D "%H:%M:%S"-d "10:33:56"+"%Y.%m.%d-%H:%M:%S"
I jak widać na podstawie powyższego polecenia, przyjmuje się, że dzień jest „dzisiaj”. Aby uzyskać czas zaczynający się od epoki:
$ string1="10:33:56"
$ date -u -D "%Y.%m.%d-%H:%M:%S"-d "1970.01.01-$string1"+"%Y.%m.%d-%H:%M:%S"1970.01.01-10:33:56
Data Busybox może nawet odbierać czas (w powyższym formacie) bez -D:
$ date -u -d "1970.01.01-$string1"+"%Y.%m.%d-%H:%M:%S"1970.01.01-10:33:56
Format wyjściowy może wynosić nawet kilka sekund od epoki.
$ date -u -d "1970.01.01-$string1"+"%s"52436
W obu przypadkach i trochę matematyki (zajęty nie potrafi jeszcze matematyki):
Ta niesamowita odpowiedź obejmowała wiele podstaw i zawierała dokładne wyjaśnienia. Dziękuję Ci!
Devy
Musiałem sprawdzić %(FORMAT)Tciąg znaków przekazany do printfpolecenia zintegrowanego z bash. Z bash-hackers.org : %(FORMAT)Twyświetl ciąg daty i godziny wynikający z użycia FORMATjako ciągu formatu strftime (3). Powiązany argument to liczba sekund od Epoki lub -1 (bieżący czas) lub -2 (czas uruchamiania powłoki). Jeśli nie podano odpowiedniego argumentu, domyślnie jest używany bieżący czas . To ezoteryczne. W tym przypadku %spodana strftime(3)jest „liczba sekund od epoki”.
Czym to się różni od mojego rozwiązania? Naprawdę nie widzę korzyści z wywołania awkw tym przypadku, ponieważ Bash równie dobrze radzi sobie z arytmetyką liczb całkowitych.
Daniel Kamil Kozar
1
Twoja odpowiedź też jest poprawna. Niektórzy ludzie, jak ja, wolą pracować z awk niż z niekonsekwencjami bash.
Dorian
2
Czy mógłbyś rozwinąć nieco więcej na temat niespójności Basha dotyczących arytmetyki liczb całkowitych? Chciałbym dowiedzieć się więcej na ten temat, ponieważ nic nie wiedziałem.
Daniel Kamil Kozar
12
Właśnie tego szukałem. Nie rozumiem krytyki tej odpowiedzi. Lubię widzieć więcej niż jedno rozwiązanie problemu. A ja jestem tym, który woli awkkomendy bash (jeśli nic poza tym, ponieważ awk działa w innych powłokach). Bardziej podobało mi się to rozwiązanie. Ale to moja osobista opinia.
rpsml
4
Zera wiodące: echo $ ((KONIEC-START)) | awk '{printf "% 02d:% 02d \ n", int (1/60 $), int (1% 60)}'
Szukałem czegoś podobnego do twojej date metody GNU . Geniusz.
Haohmaru,
Proszę usunąć mój komentarz ... przepraszam
Bill Gale
Po instalacji dateutilsprzez apt, nie było datediffkomendy - musiałem użyć dateutils.ddiff.
Suzana
12
Chciałbym zaproponować inny sposób, który pozwoli uniknąć przypominania date polecenia. Może to być pomocne w przypadku, gdy zebrałeś już znaczniki czasu w %Tformacie daty:
ts_get_sec(){
read -r h m s <<< $(echo $1 | tr ':'' ')
echo $(((h*60*60)+(m*60)+s))}
start_ts=10:33:56
stop_ts=10:36:10
START=$(ts_get_sec $start_ts)
STOP=$(ts_get_sec $stop_ts)
DIFF=$((STOP-START))
echo "$((DIFF/60))m $((DIFF%60))s"
możemy nawet obsługiwać milisekundy w ten sam sposób.
ts_get_msec(){
read -r h m s ms <<< $(echo $1 | tr '.:'' ')
echo $(((h*60*60*1000)+(m*60*1000)+(s*1000)+ms))}
start_ts=10:33:56.104
stop_ts=10:36:10.102
START=$(ts_get_msec $start_ts)
STOP=$(ts_get_msec $stop_ts)
DIFF=$((STOP-START))
min=$((DIFF/(60*1000)))
sec=$(((DIFF%(60*1000))/1000))
ms=$(((DIFF%(60*1000))%1000))
echo "${min}:${sec}.$ms"
Czy istnieje sposób na obsługę milisekund, np. 10: 33: 56.104
Umesh Rajbhandari
Obsługa milisekund źle zachowuje się, jeśli pole milisekund zaczyna się od zera. Na przykład ms = „033” da końcowe cyfry „027”, ponieważ pole ms jest interpretowane jako ósemkowe. zmiana „echo” ... ”+ ms)) na…” + $ {ms ## + (0)})) ”naprawi to tak długo, jak długo„ shopt -s extglob ”pojawi się gdzieś powyżej tego w scenariusz. Prawdopodobnie należy również usunąć wiodące zera od h, m i s ...
Eric Towers
3
echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s))))pracował dla mnie odkąd dostałemvalue too great for base (error token is "08")
Niklas
6
Oto magia:
time1=14:30
time2=$( date +%H:%M )# 16:00
diff=$( echo "$time2 - $time1"| sed 's%:%+(1/60)*%g'| bc -l )
echo $diff hours
# outputs 1.5 hours
sedzastępuje a :formułą do konwersji na 1/60. Następnie dokonuje się obliczenia czasubc
Oto rozwiązanie wykorzystujące tylko datemożliwości poleceń za pomocą „temu” i nie wykorzystujące drugiej zmiennej do przechowywania czasu zakończenia:
#!/bin/bash# save the current time
start_time=$( date +%s.%N )# tested program
sleep 1# the current time after the program has finished# minus the time when we started, in seconds.nanoseconds
elapsed_time=$( date +%s.%N --date="$start_time seconds ago")
echo elapsed_time: $elapsed_time
Niektóre przetwarzanie łańcuchów może usunąć te puste wartości
date -ujf%s $(($(date -jf%T "10:36:10"+%s)- $(date -jf%T "10:33:56"+%s))) \
+'%-Hh %-Mm %-Ss'| sed "s/[[:<:]]0[hms] *//g"# 2m 14s
To nie zadziała, jeśli umieścisz wcześniej. Jeśli musisz sobie z tym poradzić, zmień $(($(date ...) - $(date ...)))na$(echo $(date ...) - $(date ...) | bc | tr -d -)
$ units
2411 units,71 prefixes,33 nonlinear units
You have:(10hr+36min+10s)-(10hr+33min+56s)You want: s
*134/0.0074626866You have:(10hr+36min+10s)-(10hr+33min+56s)You want: min
*2.2333333/0.44776119
Zdaję sobie sprawę, że to starszy post, ale natknąłem się na niego dzisiaj, pracując nad skryptem, który pobierałby daty i godziny z pliku dziennika i obliczał różnicę. Poniższy skrypt jest z pewnością przesadny i bardzo polecam sprawdzenie mojej logiki i matematyki.
#!/bin/bash
dTime=""
tmp=""#firstEntry="$(head -n 1 "$LOG" | sed 's/.*] \([0-9: -]\+\).*/\1/')"
firstEntry="2013-01-16 01:56:37"#lastEntry="$(tac "$LOG" | head -n 1 | sed 's/.*] \([0-9: -]\+\).*/\1/')"
lastEntry="2014-09-17 18:24:02"# I like to make the variables easier to parse
firstEntry="${firstEntry//-/ }"
lastEntry="${lastEntry//-/ }"
firstEntry="${firstEntry//:/ }"
lastEntry="${lastEntry//:/ }"# remove the following lines in production
echo "$lastEntry"
echo "$firstEntry"# compute days in last entryfor i in`seq 1 $(echo $lastEntry|awk '{print $2}')`;do{case"$i"in1|3|5|7|8|10|12)
dTime=$(($dTime+31));;4|6|9|11)
dTime=$(($dTime+30));;2)
dTime=$(($dTime+28));;esac}done# do leap year calculations for all years between first and last entryfor i in`seq $(echo $firstEntry|awk '{print $1}') $(echo $lastEntry|awk '{print $1}')`;do{if[ $(($i%4))-eq 0]&&[ $(($i%100))-eq 0]&&[ $(($i%400))-eq 0];then{if["$i"="$(echo $firstEntry|awk '{print $1}')"]&&[ $(echo $firstEntry|awk '{print $2}')-lt 2];then{
dTime=$(($dTime+1))}elif[ $(echo $firstEntry|awk '{print $2}')-eq 2]&&[ $(echo $firstEntry|awk '{print $3}')-lt 29];then{
dTime=$(($dTime+1))}fi}elif[ $(($i%4))-eq 0]&&[ $(($i%100))-ne 0];then{if["$i"="$(echo $lastEntry|awk '{print $1}')"]&&[ $(echo $lastEntry|awk '{print $2}')-gt 2];then{
dTime=$(($dTime+1))}elif[ $(echo $lastEntry|awk '{print $2}')-eq 2]&&[ $(echo $lastEntry|awk '{print $3}')-ne 29];then{
dTime=$(($dTime+1))}fi}fi}done# substract days in first entryfor i in`seq 1 $(echo $firstEntry|awk '{print $2}')`;do{case"$i"in1|3|5|7|8|10|12)
dTime=$(($dTime-31));;4|6|9|11)
dTime=$(($dTime-30));;2)
dTime=$(($dTime-28));;esac}done
dTime=$(($dTime+$(echo $lastEntry|awk '{print $3}')-$(echo $firstEntry|awk '{print $3}')))# The above gives number of days for sample. Now we need hours, minutes, and seconds# As a bit of hackery I just put the stuff in the best order for use in a for loop
dTime="$(($(echo $lastEntry|awk '{print $6}')-$(echo $firstEntry|awk '{print $6}'))) $(($(echo $lastEntry|awk '{print $5}')-$(echo $firstEntry|awk '{print $5}'))) $(($(echo $lastEntry|awk '{print $4}')-$(echo $firstEntry|awk '{print $4}'))) $dTime"
tmp=1for i in $dTime;do{if[ $i -lt 0];then{case"$tmp"in1)
tmp="$(($(echo $dTime|awk '{print $1}')+60)) $(($(echo $dTime|awk '{print $2}')-1))"
dTime="$tmp $(echo $dTime|awk '{print $3""$4}')"
tmp=1;;2)
tmp="$(($(echo $dTime|awk '{print $2}')+60)) $(($(echo $dTime|awk '{print $3}')-1))"
dTime="$(echo $dTime|awk '{print $1}') $tmp $(echo $dTime|awk '{print $4}')"
tmp=2;;3)
tmp="$(($(echo $dTime|awk '{print $3}')+24)) $(($(echo $dTime|awk '{print $4}')-1))"
dTime="$(echo $dTime|awk '{print $1""$2}') $tmp"
tmp=3;;esac}fi
tmp=$(($tmp+1))}done
echo "The sample time is $(echo $dTime|awk '{print $4}') days, $(echo $dTime|awk '{print $3}') hours, $(echo $dTime|awk '{print $2}') minutes, and $(echo $dTime|awk '{print $1}') seconds."
Otrzymasz wynik w następujący sposób.
2012101601563720140917182402The sample time is 700 days,16 hours,27 minutes, and 25 seconds.
Zmodyfikowałem trochę skrypt, aby był samodzielny (tj. Po prostu ustawiał wartości zmiennych), ale być może pojawia się też ogólny pomysł. Warto sprawdzić dodatkowe błędy pod kątem wartości ujemnych.
Oto moja implementacja bash (z bitami pobranymi z innych SO ;-)
function countTimeDiff(){
timeA=$1 # 09:59:35
timeB=$2 # 17:32:55# feeding variables by using read and splitting with IFS
IFS=: read ah am as <<<"$timeA"
IFS=: read bh bm bs <<<"$timeB"# Convert hours to minutes.# The 10# is there to avoid errors with leading zeros# by telling bash that we use base 10
secondsA=$((10#$ah*60*60 + 10#$am*60 + 10#$as))
secondsB=$((10#$bh*60*60 + 10#$bm*60 + 10#$bs))
DIFF_SEC=$((secondsB - secondsA))
echo "The difference is $DIFF_SEC seconds.";
SEC=$(($DIFF_SEC%60))
MIN=$((($DIFF_SEC-$SEC)%3600/60))
HRS=$((($DIFF_SEC-$MIN*60)/3600))
TIME_DIFF="$HRS:$MIN:$SEC";
echo $TIME_DIFF;}
$ countTimeDiff 2:15:552:55:16The difference is 2361 seconds.0:39:21
time
polecenia?date +%s
, a następnie odejmij, aby uzyskać różnicę w sekundach.Odpowiedzi:
Bash ma przydatną
SECONDS
wbudowaną zmienną, która śledzi liczbę sekund, które upłynęły od uruchomienia powłoki. Ta zmienna zachowuje swoje właściwości po przypisaniu, a wartość zwracana po przypisaniu jest liczbą sekund od przypisania plus przypisana wartość.Dlatego możesz po prostu ustawić
SECONDS
0 przed rozpoczęciem zdarzenia czasowego, po prostu przeczytaćSECONDS
po zdarzeniu i wykonać arytmetykę czasu przed wyświetleniem.Ponieważ to rozwiązanie nie zależy od
date +%s
(które jest rozszerzeniem GNU), jest przenośne dla wszystkich systemów obsługiwanych przez Bash.źródło
date
w wykonaniu arytmetyki czasu, piszącdate -u -d @"$diff" +'%-Mm %-Ss'
. (To interpretuje$diff
jako sekundę od epoki i oblicza minuty i sekundy w UTC). Prawdopodobnie nie jest to już bardziej eleganckie, po prostu lepiej zaciemnione. :-Pecho "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
$(date -u +%s)
aby zapobiec wyścigowi w dniach, w których zmienia się czas letni. I strzeżcie się złych sekund przestępnych;)unset SECONDS
jej zniknięciu:echo $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
sekundy
Do pomiaru upływu czasu (w sekundach) potrzebujemy:
Liczba całkowita upływających sekund:
Istnieją dwa wewnętrzne sposoby na znalezienie wartości całkowitej dla liczby upływających sekund:
Zmienna Bash SECONDS (jeśli nie ustawiono SECONDS, traci swoją specjalną właściwość).
Ustawienie wartości SECONDS na 0:
Przechowywanie wartości zmiennej
SECONDS
na początku:Opcja Bash printf
%(datefmt)T
:Konwertuj taką liczbę całkowitą na użyteczny format
Bash wewnętrzny
printf
może to zrobić bezpośrednio:podobnie
ale to nie powiedzie się na dłużej niż 24 godziny, ponieważ tak naprawdę drukujemy czas naścienny, a nie czas trwania:
Dla miłośników szczegółów z bash-hackers.org :
Możesz więc zadzwonić,
textifyDuration $elpasedseconds
gdzietextifyDuration
jest jeszcze jedna implementacja drukowania czasu trwania:Data GNU.
Aby uzyskać sformatowany czas, powinniśmy skorzystać z zewnętrznego narzędzia (data GNU) na kilka sposobów, aby osiągnąć długość prawie roku, w tym nanosekundy.
Matematyka w dacie.
Nie ma potrzeby stosowania zewnętrznej arytmetyki, zrób to wszystko w jednym kroku
date
:Tak,
0
w wierszu polecenia jest zero. To jest potrzebne.Zakłada się, że możesz zmienić
date +"%T"
polecenie nadate +"%s"
polecenie, aby wartości zostały zapisane (wydrukowane) w kilka sekund.Pamiętaj, że polecenie jest ograniczone do:
$StartDate
i$FinalDate
sekundy.$FinalDate
jest większa (później) niż$StartDate
.Jeśli musisz użyć
10:33:56
ciągu, cóż, po prostu przekonwertuj go na sekundy,również słowo sekundy może być skrócone jako sec:
Zwróć uwagę, że przeliczenie czasu w sekundach (jak pokazano powyżej) odnosi się do początku „tego” dnia (dziś).
Pojęcie to można rozszerzyć na nanosekundy, takie jak to:
Jeśli wymagane jest obliczenie dłuższych (do 364 dni) różnic czasowych, musimy użyć początku (jakiegoś) roku jako wartości odniesienia i wartości formatu
%j
(numeru dnia w roku):Podobny do:
Niestety, w tym przypadku musimy ręcznie odjąć
1
JEDEN od liczby dni. Polecenie daty wyświetla pierwszy dzień roku jako 1. Nie jest to trudne ...Wykorzystanie dużej liczby sekund jest prawidłowe i udokumentowane tutaj:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
Data zajętości
Narzędzie używane w mniejszych urządzeniach (bardzo mały plik wykonywalny do zainstalowania): Busybox.
Utwórz link do busyboksa o nazwie data:
Użyj go następnie, wywołując to
date
(umieść w katalogu zawierającym ŚCIEŻKĘ).Lub stwórz alias:
Data Busybox ma fajną opcję: -D, aby otrzymać format godziny wejściowej. Otwiera to wiele formatów, które można wykorzystać jako czas. Za pomocą opcji -D możemy bezpośrednio przekonwertować czas 10:33:56:
I jak widać na podstawie powyższego polecenia, przyjmuje się, że dzień jest „dzisiaj”. Aby uzyskać czas zaczynający się od epoki:
Data Busybox może nawet odbierać czas (w powyższym formacie) bez -D:
Format wyjściowy może wynosić nawet kilka sekund od epoki.
W obu przypadkach i trochę matematyki (zajęty nie potrafi jeszcze matematyki):
Lub sformatowane:
źródło
%(FORMAT)T
ciąg znaków przekazany doprintf
polecenia zintegrowanego z bash. Z bash-hackers.org :%(FORMAT)T
wyświetl ciąg daty i godziny wynikający z użyciaFORMAT
jako ciągu formatu strftime (3). Powiązany argument to liczba sekund od Epoki lub -1 (bieżący czas) lub -2 (czas uruchamiania powłoki). Jeśli nie podano odpowiedniego argumentu, domyślnie jest używany bieżący czas . To ezoteryczne. W tym przypadku%s
podanastrftime(3)
jest „liczba sekund od epoki”.Oto jak to zrobiłem:
Naprawdę proste, weź liczbę sekund na początku, a następnie weź liczbę sekund na końcu i wydrukuj różnicę w minutach: sekundach.
źródło
awk
w tym przypadku, ponieważ Bash równie dobrze radzi sobie z arytmetyką liczb całkowitych.awk
komendy bash (jeśli nic poza tym, ponieważ awk działa w innych powłokach). Bardziej podobało mi się to rozwiązanie. Ale to moja osobista opinia.Inną opcją jest skorzystanie
datediff
zdateutils
( http://www.fresse.org/dateutils/#datediff ):Możesz także użyć
gawk
.mawk
1.3.4 posiada równieżstrftime
amktime
jednak starsze wersjemawk
inawk
nie.Lub oto inny sposób, aby to zrobić z GNU
date
:źródło
date
metody GNU . Geniusz.dateutils
przez apt, nie byłodatediff
komendy - musiałem użyćdateutils.ddiff
.Chciałbym zaproponować inny sposób, który pozwoli uniknąć przypominania
date
polecenia. Może to być pomocne w przypadku, gdy zebrałeś już znaczniki czasu w%T
formacie daty:możemy nawet obsługiwać milisekundy w ten sam sposób.
źródło
echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s))))
pracował dla mnie odkąd dostałemvalue too great for base (error token is "08")
Oto magia:
sed
zastępuje a:
formułą do konwersji na 1/60. Następnie dokonuje się obliczenia czasubc
źródło
Na dzień dzisiejszy (GNU coreutils) 7.4 możesz teraz używać -d do arytmetyki:
Jednostki, których możesz użyć, to dni, lata, miesiące, godziny, minuty i sekundy:
źródło
Kontynuując odpowiedź Daniela Kamila Kozara, aby pokazać godziny / minuty / sekundy:
Pełny skrypt byłby więc:
źródło
Lub trochę zawiń
To działa.
źródło
Oto rozwiązanie wykorzystujące tylko
date
możliwości poleceń za pomocą „temu” i nie wykorzystujące drugiej zmiennej do przechowywania czasu zakończenia:to daje:
źródło
źródło
date
.date
może dać ci różnicę i sformatować ją dla ciebie (pokazane opcje OS X)Niektóre przetwarzanie łańcuchów może usunąć te puste wartości
To nie zadziała, jeśli umieścisz wcześniej. Jeśli musisz sobie z tym poradzić, zmień
$(($(date ...) - $(date ...)))
na$(echo $(date ...) - $(date ...) | bc | tr -d -)
źródło
Potrzebowałem skryptu różnicy czasu do użycia z
mencoder
(--endpos
jest względny), a moim rozwiązaniem jest wywołanie skryptu Python:obsługiwane są również ułamki sekund:
i może powiedzieć, że różnica między 200 a 120 wynosi 1h 20m:
i może konwertować dowolną (prawdopodobnie ułamkową) liczbę sekund lub minut lub godzin na hh: mm: ss
timediff.py:
źródło
Z GNU
units
:źródło
Uogólnienie rozwiązania @ nisetama przy użyciu daty GNU (zaufane Ubuntu 14.04 LTS):
wydajność:
źródło
źródło
Zdefiniuj tę funkcję (powiedzmy w ~ / .bashrc):
Teraz możesz mierzyć czas części swoich skryptów:
bardzo przydatne, aby znaleźć wąskie gardła wykonania.
źródło
Zdaję sobie sprawę, że to starszy post, ale natknąłem się na niego dzisiaj, pracując nad skryptem, który pobierałby daty i godziny z pliku dziennika i obliczał różnicę. Poniższy skrypt jest z pewnością przesadny i bardzo polecam sprawdzenie mojej logiki i matematyki.
Otrzymasz wynik w następujący sposób.
Zmodyfikowałem trochę skrypt, aby był samodzielny (tj. Po prostu ustawiał wartości zmiennych), ale być może pojawia się też ogólny pomysł. Warto sprawdzić dodatkowe błędy pod kątem wartości ujemnych.
źródło
Nie mogę skomentować odpowiedzi mcaleaa, dlatego zamieszczam to tutaj. Zmienna „diff” powinna znajdować się na małych literach. Oto przykład.
Poprzednia zmienna została zadeklarowana małymi literami. Tak się stało, gdy użyto wielkich liter.
Tak więc szybka naprawa byłaby taka
źródło
Oto moja implementacja bash (z bitami pobranymi z innych SO ;-)
Nie testowany, może być wadliwy.
źródło