Come calcolare il tempo trascorso nello script bash?


224

Stampa l'ora di inizio e fine usando date +"%T", il che si traduce in qualcosa di simile:

10:33:56
10:36:10

Come potrei calcolare e stampare la differenza tra questi due?

Vorrei ottenere qualcosa del tipo:

2m 14s

5
In un'altra nota, non potresti usare il timecomando?
anishsane,

Usa invece unix time date +%s, quindi sottrai per ottenere la differenza in secondi.
roblogic,

Risposte:


476

Bash ha una pratica SECONDSvariabile integrata che tiene traccia del numero di secondi trascorsi dall'avvio della shell. Questa variabile conserva le sue proprietà quando assegnata a, e il valore restituito dopo l'assegnazione è il numero di secondi dall'assegnazione più il valore assegnato.

Quindi, puoi semplicemente impostare SECONDSsu 0 prima di iniziare l'evento a tempo, leggere semplicemente SECONDSdopo l'evento e fare l'aritmetica del tempo prima di visualizzarlo.

SECONDS=0
# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."

Poiché questa soluzione non dipende da date +%s(che è un'estensione GNU), è portatile per tutti i sistemi supportati da Bash.


59
+1. Per inciso, puoi ingannare l' dateesecuzione dell'aritmetica del tempo per te, scrivendo date -u -d @"$diff" +'%-Mm %-Ss'. (Che interpreta $diffi secondi dall'epoca e calcola i minuti e i secondi in UTC.) Probabilmente non è più elegante, però, solo meglio offuscato. :-P
ruakh

13
Bello e semplice. Se qualcuno ha bisogno di ore:echo "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
chus

6
Dovrebbe essere letto $(date -u +%s)per evitare una condizione di gara nelle date in cui l'ora legale viene cambiata. E attenzione ai secondi bisestili del male;)
Tino,

3
@ daniel-kamil-kozar Nice find. Tuttavia, questo è un po 'fragile. Esiste solo una di queste variabili, quindi non può essere utilizzata in modo ricorsivo per misurare le prestazioni, e ancora peggio, dopo unset SECONDSche è sparita:echo $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
Tino

6
@ParthianShot: mi dispiace che tu la pensi così. Tuttavia, credo che questa risposta sia ciò di cui molte persone hanno bisogno durante la ricerca di risposte a una domanda come questa: misurare quanto tempo è passato tra gli eventi, non calcolare il tempo.
Daniel Kamil Kozar,

99

secondi

Per misurare il tempo trascorso (in secondi) abbiamo bisogno di:

  • un numero intero che rappresenta il conteggio dei secondi trascorsi e
  • un modo per convertire tale numero intero in un formato utilizzabile.

Un valore intero di secondi trascorsi:

  • Esistono due modi interni bash per trovare un valore intero per il numero di secondi trascorsi:

    1. Variabile di Bash SECONDI (se SECONDI non è impostato, perde la sua proprietà speciale).

      • Impostando il valore di SECONDS su 0:

        SECONDS=0
        sleep 1  # Process to execute
        elapsedseconds=$SECONDS
      • Memorizzare il valore della variabile SECONDSall'inizio:

        a=$SECONDS
        sleep 1  # Process to execute
        elapsedseconds=$(( SECONDS - a ))
    2. Opzione 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 ))

Converti tale numero intero in un formato utilizzabile

Il bash interno printfpuò farlo direttamente:

$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45

allo stesso modo

$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34

ma questo non funzionerà per una durata superiore a 24 ore, poiché in realtà stampiamo un tempo di orologio da parete, non proprio una durata:

$ hours=30;mins=12;secs=24
$ elapsedseconds=$(( ((($hours*60)+$mins)*60)+$secs ))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
06:12:24

Per gli amanti dei dettagli, da bash-hackers.org :

%(FORMAT)Tgenera la stringa data-ora risultante dall'uso di FORMATO come stringa di formato per strftime(3). L'argomento associato è il numero di secondi trascorsi Epoch , o -1 (ora attuale) o -2 (tempo di avvio shell). Se non viene fornito alcun argomento corrispondente, l'ora corrente viene utilizzata come impostazione predefinita.

Quindi potresti voler chiamare solo textifyDuration $elpasedsecondsdove textifyDurationc'è ancora un'altra implementazione della stampa della durata:

textifyDuration() {
   local duration=$1
   local shiff=$duration
   local secs=$((shiff % 60));  shiff=$((shiff / 60));
   local mins=$((shiff % 60));  shiff=$((shiff / 60));
   local hours=$shiff
   local splur; if [ $secs  -eq 1 ]; then splur=''; else splur='s'; fi
   local mplur; if [ $mins  -eq 1 ]; then mplur=''; else mplur='s'; fi
   local hplur; if [ $hours -eq 1 ]; then hplur=''; else hplur='s'; fi
   if [[ $hours -gt 0 ]]; then
      txt="$hours hour$hplur, $mins minute$mplur, $secs second$splur"
   elif [[ $mins -gt 0 ]]; then
      txt="$mins minute$mplur, $secs second$splur"
   else
      txt="$secs second$splur"
   fi
   echo "$txt (from $duration seconds)"
}

Data GNU.

Per ottenere il tempo formulato dovremmo usare uno strumento esterno (data GNU) in diversi modi per arrivare fino a quasi un anno e inclusi i nanosecondi.

Appuntamento matematico.

Non c'è bisogno di aritmetica esterna, fai tutto in un solo passaggio date:

date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"

Sì, c'è uno 0zero nella stringa di comando. È necessario.

Ciò presuppone che sia possibile modificare il date +"%T"comando in un date +"%s"comando in modo che i valori vengano memorizzati (stampati) in pochi secondi.

Si noti che il comando è limitato a:

  • Valori positivi di $StartDatee $FinalDatesecondi.
  • Il valore in $FinalDateè maggiore (più avanti nel tempo) di $StartDate.
  • Differenza di tempo inferiore a 24 ore.
  • Accettate un formato di output con Ore, Minuti e Secondi. Molto facile da cambiare.
  • È accettabile usare -u volte UTC. Per evitare "DST" e correzioni dell'ora locale.

Se devi usare la 10:33:56stringa, beh, convertila in secondi,
inoltre, la parola secondi potrebbe essere abbreviata in sec:

string1="10:33:56"
string2="10:36:10"
StartDate=$(date -u -d "$string1" +"%s")
FinalDate=$(date -u -d "$string2" +"%s")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S"

Si noti che la conversione del tempo in secondi (come presentato sopra) è relativa all'inizio di "questo" giorno (Oggi).


Il concetto potrebbe essere esteso a nanosecondi, in questo modo:

string1="10:33:56.5400022"
string2="10:36:10.8800056"
StartDate=$(date -u -d "$string1" +"%s.%N")
FinalDate=$(date -u -d "$string2" +"%s.%N")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S.%N"

Se è necessario calcolare differenze di tempo più lunghe (fino a 364 giorni), dobbiamo utilizzare l'inizio di (alcuni) anni come riferimento e il valore del formato %j(il numero del giorno nell'anno):

Simile a:

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

Purtroppo, in questo caso, dobbiamo sottrarre manualmente 1ONE dal numero di giorni. Il comando data visualizza il primo giorno dell'anno come 1. Non così difficile ...

a=( $(date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N") )
a[0]=$((10#${a[0]}-1)); echo "${a[@]}"



L'uso di un lungo numero di secondi è valido e documentato qui:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date


Data di occupato

Uno strumento utilizzato in dispositivi più piccoli (un eseguibile molto piccolo da installare): Busybox.

O crea un collegamento a busybox chiamato date:

$ ln -s /bin/busybox date

Usalo quindi chiamando questo date(posizionalo in una directory inclusa PERCORSO).

O crea un alias come:

$ alias date='busybox date'

La data di Busybox ha una bella opzione MrGreen per ricevere il formato dell'ora di input. Questo apre molti formati da usare come tempo. Usando l'opzione -D possiamo convertire direttamente l'ora 10:33:56:

date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"

E come puoi vedere dall'output del comando sopra, si presume che il giorno sia "oggi". Per iniziare a partire dall'epoca:

$ 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

La data di Busybox può persino ricevere l'ora (nel formato sopra) senza -D:

$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56

E il formato di output potrebbe anche essere secondi dall'epoca.

$ date -u -d "1970.01.01-$string1" +"%s"
52436

Per entrambe le volte, e un po 'di matematica bash (la scatola occupata non può ancora fare la matematica):

string1="10:33:56"
string2="10:36:10"
t1=$(date -u -d "1970.01.01-$string1" +"%s")
t2=$(date -u -d "1970.01.01-$string2" +"%s")
echo $(( t2 - t1 ))

O formattato:

$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14

6
Questa è una risposta così sorprendente che ha coperto molte basi e con buone spiegazioni. Grazie!
Devy,

Ho dovuto cercare la %(FORMAT)Tstringa passata al printfcomando integrato in bash. Da bash-hackers.org : genera %(FORMAT)Tla stringa data-ora risultante dall'uso FORMATcome stringa di formato per strftime (3). L'argomento associato è il numero di secondi dall'epoca, oppure -1 (ora corrente) o -2 (ora di avvio della shell). Se non viene fornito alcun argomento corrispondente, l'ora corrente viene utilizzata come impostazione predefinita . È esoterico. In questo caso, %scome indicato a strftime(3)è "il numero di secondi dall'epoca".
David Tonhofer,

35

Ecco come l'ho fatto:

START=$(date +%s);
sleep 1; # Your stuff
END=$(date +%s);
echo $((END-START)) | awk '{print int($1/60)":"int($1%60)}'

Davvero semplice, prendi il numero di secondi all'inizio, quindi prendi il numero di secondi alla fine e stampa la differenza in minuti: secondi.


6
In che modo differisce dalla mia soluzione? In awkquesto caso non riesco davvero a vedere il vantaggio di chiamare , dal momento che Bash gestisce l'aritmetica intera ugualmente bene.
Daniel Kamil Kozar,

1
Anche la tua risposta è corretta. Alcune persone, come me, preferiscono lavorare con awk piuttosto che con incoerenze bash.
Dorian,

2
Potresti approfondire un po 'di più sulle incongruenze di Bash riguardo l'aritmetica dei numeri interi? Mi piacerebbe saperne di più su questo, dal momento che non ne ero a conoscenza.
Daniel Kamil Kozar,

12
Lo stavo solo cercando. Non capisco le critiche a questa risposta. Mi piace vedere più di una soluzione a un problema. E io sono uno che preferisce i awkcomandi a bash (se non altro, perché awk funziona in altre shell). Questa soluzione mi è piaciuta di più. Ma questa è la mia opinione personale.
rpsml,

4
Zeri iniziali: echo $ ((END-START)) | awk '{printf "% 02d:% 02d \ n", int ($ 1/60), int ($ 1% 60)}'
Jon Strayer,

17

Un'altra opzione è quella di utilizzare datediffda dateutils( http://www.fresse.org/dateutils/#datediff ):

$ datediff 10:33:56 10:36:10
134s
$ datediff 10:33:56 10:36:10 -f%H:%M:%S
0:2:14
$ datediff 10:33:56 10:36:10 -f%0H:%0M:%0S
00:02:14

Puoi anche usare gawk. mawk1.3.4 ha anche strftimee mktimema versioni precedenti di mawke nawknon.

$ TZ=UTC0 awk 'BEGIN{print strftime("%T",mktime("1970 1 1 10 36 10")-mktime("1970 1 1 10 33 56"))}'
00:02:14

Oppure ecco un altro modo per farlo con GNU date:

$ date -ud@$(($(date -ud'1970-01-01 10:36:10' +%s)-$(date -ud'1970-01-01 10:33:56' +%s))) +%T
00:02:14

1
Stavo cercando qualcosa come il tuo date metodo GNU . Genio.
Haohmaru,

Elimina il mio commento ... scusa
Bill Gale,

Dopo l'installazione dateutilstramite apt, non vi era alcun datediffcomando - da usare dateutils.ddiff.
Suzana,

12

Vorrei proporre un altro modo per evitare di richiamare il datecomando. Può essere utile nel caso in cui tu abbia già raccolto i timestamp nel %Tformato data:

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"

possiamo persino gestire i millisecondi allo stesso modo.

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"

1
C'è un modo per gestire i milliseconi, ad esempio 10: 33: 56.104
Umesh Rajbhandari,

La gestione dei millisecondi si comporta in modo anomalo se il campo dei millisecondi inizia con uno zero. Ad esempio ms = "033" fornirà cifre finali di "027" perché il campo ms viene interpretato come ottale. la modifica di "echo" ... "+ ms))" in ... "+ $ {ms ## + (0)}))" risolverà il problema finché "shopt -s extglob" appare da qualche parte sopra script. Uno dovrebbe probabilmente eliminare gli zeri iniziali anche da h, m e s ...
Eric Towers

3
echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s))))ha funzionato per me da quando ho avutovalue too great for base (error token is "08")
Niklas

6

Ecco un po 'di 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

sedsostituisce a :con una formula per convertire in 1/60. Quindi il calcolo del tempo effettuato dabc


5

A partire da data (GNU coreutils) 7.4 ora puoi usare -d per fare l'aritmetica:

$ date -d -30days
Sat Jun 28 13:36:35 UTC 2014

$ date -d tomorrow
Tue Jul 29 13:40:55 UTC 2014

Le unità che è possibile utilizzare sono giorni, anni, mesi, ore, minuti e secondi:

$ date -d tomorrow+2days-10minutes
Thu Jul 31 13:33:02 UTC 2014

3

Seguendo la risposta di Daniel Kamil Kozar, per mostrare ore / minuti / secondi:

echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"

Quindi lo script completo sarebbe:

date1=$(date +"%s")
date2=$(date +"%s")
diff=$(($date2-$date1))
echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"

3

O avvolgilo un po '

alias timerstart='starttime=$(date +"%s")'
alias timerstop='echo seconds=$(($(date +"%s")-$starttime))'

Quindi funziona.

timerstart; sleep 2; timerstop
seconds=2

3

Ecco una soluzione che utilizza solo le datefunzionalità dei comandi che utilizzano "ago" e non utilizza una seconda variabile per memorizzare l'ora di fine:

#!/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

questo da:

$ ./time_elapsed.sh 
elapsed_time: 1.002257120

2
% start=$(date +%s)
% echo "Diff: $(date -d @$(($(date +%s)-$start)) +"%M minutes %S seconds")"
Diff: 00 minutes 11 seconds

6
Sarebbe utile sapere cosa fa questa risposta che le altre risposte non fanno.
Louis,

Ti consente di stampare facilmente la durata in qualsiasi formato consentito da date.
Ryan C. Thompson,

2

date può darti la differenza e formattarla per te (mostrate le opzioni di OS X)

date -ujf%s $(($(date -jf%T "10:36:10" +%s) - $(date -jf%T "10:33:56" +%s))) +%T
# 00:02:14

date -ujf%s $(($(date -jf%T "10:36:10" +%s) - $(date -jf%T "10:33:56" +%s))) \
    +'%-Hh %-Mm %-Ss'
# 0h 2m 14s

Alcune elaborazioni di stringhe possono rimuovere quei valori vuoti

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

Questo non funzionerà se si posiziona prima la prima volta. Se è necessario gestirlo, passare $(($(date ...) - $(date ...)))a$(echo $(date ...) - $(date ...) | bc | tr -d -)


1

Avevo bisogno di uno script di differenza di tempo da utilizzare con mencoder( --endposè relativo) e la mia soluzione è quella di chiamare uno script Python:

$ ./timediff.py 1:10:15 2:12:44
1:02:29

sono supportate anche frazioni di secondo:

$ echo "diff is `./timediff.py 10:51.6 12:44` (in hh:mm:ss format)"
diff is 0:01:52.4 (in hh:mm:ss format)

e può dirti che la differenza tra 200 e 120 è 1h 20m:

$ ./timediff.py 120:0 200:0
1:20:0

e può convertire qualsiasi numero (probabilmente frazionario) di secondi, minuti o ore in hh: mm: ss

$ ./timediff.py 0 3600
1:00:0
$ ./timediff.py 0 3.25:0:0
3:15:0

timediff.py:

#!/usr/bin/python

import sys

def x60(h,m):
    return 60*float(h)+float(m)

def seconds(time):
    try:
       h,m,s = time.split(':')
       return x60(x60(h,m),s)
    except ValueError:
       try:
          m,s = time.split(':')
          return x60(m,s)
       except ValueError:
          return float(time)

def difftime(start, end):
    d = seconds(end) - seconds(start)
    print '%d:%02d:%s' % (d/3600,d/60%60,('%02f' % (d%60)).rstrip('0').rstrip('.'))

if __name__ == "__main__":
   difftime(sys.argv[1],sys.argv[2])

1

Con GNU units:

$ units
2411 units, 71 prefixes, 33 nonlinear units
You have: (10hr+36min+10s)-(10hr+33min+56s)
You want: s
    * 134
    / 0.0074626866
You have: (10hr+36min+10s)-(10hr+33min+56s)
You want: min
    * 2.2333333
    / 0.44776119

1

Generalizzando la soluzione di @nisetama usando la data GNU (fidata Ubuntu 14.04 LTS):

start=`date`
# <processing code>
stop=`date`
duration=`date -ud@$(($(date -ud"$stop" +%s)-$(date -ud"$start" +%s))) +%T`

echo $start
echo $stop
echo $duration

cedendo:

Wed Feb 7 12:31:16 CST 2018
Wed Feb 7 12:32:25 CST 2018
00:01:09

1
#!/bin/bash

START_TIME=$(date +%s)

sleep 4

echo "Total time elapsed: $(date -ud "@$(($(date +%s) - $START_TIME))" +%T) (HH:MM:SS)"
$ ./total_time_elapsed.sh 
Total time elapsed: 00:00:04 (HH:MM:SS)

1

Definire questa funzione (ad esempio in ~ / .bashrc):

time::clock() {
    [ -z "$ts" ]&&{ ts=`date +%s%N`;return;}||te=`date +%s%N`
    printf "%6.4f" $(echo $((te-ts))/1000000000 | bc -l)
    unset ts te
}

Ora puoi misurare il tempo di parti dei tuoi script:

$ cat script.sh
# ... code ...
time::clock
sleep 0.5
echo "Total time: ${time::clock}"
# ... more code ...

$ ./script.sh
Total time: 0.5060

molto utile per trovare colli di bottiglia nell'esecuzione.


0

Mi rendo conto che questo è un post più vecchio, ma l'ho trovato oggi mentre stavo lavorando su uno script che avrebbe preso date e ore da un file di registro e avrebbe calcolato il delta. Lo script di seguito è sicuramente eccessivo e consiglio vivamente di controllare la mia logica e la mia matematica.

#!/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 entry
for i in `seq 1 $(echo $lastEntry|awk '{print $2}')`; do {
  case "$i" in
   1|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 entry
for 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 entry
for i in `seq 1 $(echo $firstEntry|awk '{print $2}')`; do {
  case "$i" in
   1|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=1
for i in $dTime; do {
  if [ $i -lt 0 ]; then {
    case "$tmp" in
     1 )
      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."

Otterrai un output come segue.

2012 10 16 01 56 37
2014 09 17 18 24 02
The sample time is 700 days, 16 hours, 27 minutes, and 25 seconds.

Ho modificato un po 'lo script per renderlo autonomo (ovvero impostare solo valori variabili), ma forse anche l'idea generale si presenta. Potresti desiderare qualche errore aggiuntivo nel controllo dei valori negativi.


Accidenti, molto lavoro !! Si prega di guardare la mia risposta: stackoverflow.com/a/24996647/2350426

0

Non posso commentare la risposta di mcaleaa, quindi inserisco questo qui. La variabile "diff" dovrebbe essere in minuscolo. Ecco un esempio

[root@test ~]# date1=$(date +"%s"); date
Wed Feb 21 23:00:20 MYT 2018
[root@test ~]# 
[root@test ~]# date2=$(date +"%s"); date
Wed Feb 21 23:00:33 MYT 2018
[root@test ~]# 
[root@test ~]# diff=$(($date2-$date1))
[root@test ~]# 

La variabile precedente è stata dichiarata in minuscolo. Questo è ciò che è accaduto quando si utilizza la maiuscola.

[root@test ~]# echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"
-bash: / 3600 : syntax error: operand expected (error token is "/ 3600 ")
[root@test ~]# 

Quindi, la soluzione rapida sarebbe così

[root@test ~]# echo "Duration: $(($diff / 3600 )) hours $((($diff % 3600) / 60)) minutes $(($diff % 60)) seconds"
Duration: 0 hours 0 minutes 13 seconds
[root@test ~]# 

-1

Ecco la mia implementazione bash (con bit presi da altri 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:55 2:55:16
The difference is 2361 seconds.
0:39:21

Non testato, potrebbe essere difettoso.

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.