Em outra nota, você não poderia usar o timecomando?
Anishsane 11/11
Use o tempo unix e date +%s, em seguida, subtraia para obter a diferença em segundos.
roblogic
Respostas:
476
O Bash possui uma SECONDSvariável interna útil que rastreia o número de segundos que passaram desde que o shell foi iniciado. Essa variável mantém suas propriedades quando atribuída a, e o valor retornado após a atribuição é o número de segundos desde a atribuição mais o valor atribuído.
Assim, você pode simplesmente definir SECONDScomo 0 antes de iniciar o evento cronometrado, simplesmente ler SECONDSapós o evento e fazer a aritmética da hora antes da exibição.
SECONDS=0# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."
Como essa solução não depende date +%s(que é uma extensão GNU), é portátil para todos os sistemas suportados pelo Bash.
+1. Aliás, você pode enganar datea execução da aritmética do tempo para você, escrevendo date -u -d @"$diff" +'%-Mm %-Ss'. (Isso interpreta $diffcomo segundos desde a época e calcula os minutos e segundos no UTC.) Isso provavelmente não é mais elegante, porém, apenas melhor ofuscado. :-P
ruakh 17/01
13
Agradável e simples. Se alguém precisar de horas:echo "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
chus 19/05/2015
6
Deve ler $(date -u +%s)para evitar uma condição de corrida nas datas em que o horário de verão é alterado. E cuidado com os maus segundos de salto;)
Tino
3
@ daniel-kamil-kozar Bom achado. No entanto, isso é um pouco frágil. Existe apenas uma variável desse tipo, portanto ela não pode ser usada recursivamente para medir o desempenho e, pior ainda, depois que unset SECONDSela desaparecer:echo $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
Tino
6
@ParthianShot: Sinto muito que você pense assim. No entanto, acredito que esta resposta é o que a maioria das pessoas precisa enquanto procura respostas para uma pergunta como esta: medir quanto tempo passou entre os eventos, não calcular o tempo.
Daniel Kamil Kozar 23/02
99
Segundos
Para medir o tempo decorrido (em segundos), precisamos:
um número inteiro que representa a contagem de segundos decorridos e
uma maneira de converter esse número inteiro em um formato utilizável.
Um valor inteiro de segundos decorridos:
Existem duas maneiras internas do bash para encontrar um valor inteiro para o número de segundos decorridos:
Variável de bash SECONDS (se SECONDS estiver desativado, ele perde sua propriedade especial).
Configurando o valor de SECONDS para 0:
SECONDS=0
sleep 1# Process to execute
elapsedseconds=$SECONDS
Armazenando o valor da variável SECONDSno início:
a=$SECONDS
sleep 1# Process to execute
elapsedseconds=$(( SECONDS - a ))
Opção 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 ))
Converta esse número inteiro em um formato utilizável
%(FORMAT)Tgera a string de data e hora resultante do uso de FORMAT como uma string de formato para strftime(3). O argumento associado é o número de segundos desde a época , ou -1 (hora atual) ou -2 (hora de inicialização do shell). Se nenhum argumento correspondente for fornecido, o horário atual será usado como padrão.
Portanto, convém ligar para textifyDuration $elpasedsecondsonde textifyDurationestá mais uma implementação da impressão por duração:
Se for necessário calcular diferenças de tempo mais longas (até 364 dias), devemos usar o início de (alguns) anos como referência e o valor do formato %j(o número do dia no ano):
Igual 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
Infelizmente, nesse caso, precisamos subtrair manualmente 1UM do número de dias. O comando date exibe o primeiro dia do ano como 1. Não é tão difícil ...
Uma ferramenta usada em dispositivos menores (um executável muito pequeno para instalar): Busybox.
Crie um link para o busybox chamado data:
$ ln -s /bin/busybox date
Use-o e chame-o date(coloque-o em um diretório incluído no PATH).
Ou crie um alias como:
$ alias date='busybox date'
A data do Busybox tem uma boa opção: -D para receber o formato do horário de entrada. Isso abre muitos formatos para serem usados com o tempo. Usando a opção -D, podemos converter o tempo 10:33:56 diretamente:
date -D "%H:%M:%S"-d "10:33:56"+"%Y.%m.%d-%H:%M:%S"
E como você pode ver na saída do comando acima, presume-se que o dia seja "hoje". Para começar o tempo na época:
$ 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
A data do Busybox pode até receber a hora (no formato acima) sem -D:
$ date -u -d "1970.01.01-$string1"+"%Y.%m.%d-%H:%M:%S"1970.01.01-10:33:56
E o formato de saída pode até demorar alguns segundos desde a época.
$ date -u -d "1970.01.01-$string1"+"%s"52436
Nas duas vezes e um pouco de matemática bash (o busybox ainda não pode fazer as contas):
Esta é uma resposta tão surpreendente que cobriu muitas bases e com boas explicações. Obrigado!
Devy
Eu tive que procurar a %(FORMAT)Tsequência passada para o printfcomando integrado no bash. Em bash-hackers.org : imprima %(FORMAT)Ta string de data e hora resultante do uso FORMATcomo string de formato para strftime (3). O argumento associado é o número de segundos desde a Época, ou -1 (hora atual) ou -2 (hora de inicialização do shell). Se nenhum argumento correspondente for suprimento, o horário atual será usado como padrão . Isso é esotérico. Nesse caso, %scomo indicado strftime(3)é "o número de segundos desde a época".
Como isso é diferente da minha solução? Eu realmente não vejo o benefício de chamar awkneste caso, já que o Bash lida com aritmética inteira igualmente bem.
precisa saber é o seguinte
1
Sua resposta também está correta. Algumas pessoas, como eu, preferem trabalhar com awk do que com inconsistências do bash.
Dorian
2
Você poderia elaborar um pouco mais sobre as inconsistências no Bash relacionadas à aritmética de números inteiros? Gostaria de saber mais sobre isso, já que não estava ciente de nada.
Daniel Kamil Kozar
12
Eu só estava procurando por isso. Não entendo as críticas a esta resposta. Eu gosto de ver mais de uma solução para um problema. E eu sou o que prefere awkcomandos para bash (se não for por mais nada, porque o awk funciona em outros shells). Gostei mais desta solução. Mas essa é a minha opinião pessoal.
rpsml
4
Zeros à esquerda: echo $ ((END-START)) | awk '{printf "% 02d:% 02d \ n", int ($ 1/60), int ($ 1% 60)}'
Eu estava procurando algo como o seu date método GNU . Gênio.
Haohmaru
Por favor, apague o meu comentário ... desculpe
Bill Gale
Após a instalação dateutilsvia apt, não havia datediffcomando - tinha que usar dateutils.ddiff.
Suzana
12
Eu gostaria de propor outra maneira que evite recuperar o datecomando. Pode ser útil se você já tiver coletado registros de %Tdata e hora no formato de 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"
podemos até lidar com milissegundos da mesma maneira.
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"
Existe uma maneira de millisecons punho, por exemplo, 10: 33: 56,104
Umesh Rajbhandari
A manipulação de milissegundos se comporta mal se o campo de milissegundos começar com um zero. Por exemplo, ms = "033" fornecerá dígitos finais de "027" porque o campo ms está sendo interpretado como octal. alterar "eco" ... "+ ms))" para ... "+ $ {ms ## + (0)}))" corrigirá isso enquanto "shopt-s extglob" aparecer em algum lugar acima disso no roteiro. Deve-se, provavelmente, tira zeros à esquerda de h, m, e é bem ...
Eric Torres
3
echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s))))trabalhou para mim desde que chegueivalue too great for base (error token is "08")
Niklas
6
Aqui está um pouco de mágica:
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
sedsubstitui a :por uma fórmula para converter para 1/60. Em seguida, o cálculo do tempo feito porbc
Aqui está uma solução usando apenas os daterecursos de comandos usando "atrás" e não usando uma segunda variável para armazenar o tempo de término:
#!/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
Algum processamento de cadeia pode remover esses valores vazios
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
Isso não funcionará se você colocar o horário anterior primeiro. Se você precisar lidar com isso, mude $(($(date ...) - $(date ...)))para$(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
Sei que essa é uma postagem mais antiga, mas hoje a encontrei enquanto trabalhava em um script que usava datas e horas de um arquivo de log e calculava o delta. O script abaixo certamente é um exagero, e eu recomendo verificar minha lógica e matemática.
#!/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."
Você obterá a saída da seguinte maneira.
2012101601563720140917182402The sample time is 700 days,16 hours,27 minutes, and 25 seconds.
Modifiquei um pouco o script para torná-lo independente (ou seja, basta definir valores variáveis), mas talvez a ideia geral também seja apresentada. Você pode querer uma verificação de erro adicional para valores negativos.
Aqui está minha implementação bash (com bits retirados de outros 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
comando?date +%s
, em seguida, subtraia para obter a diferença em segundos.Respostas:
O Bash possui uma
SECONDS
variável interna útil que rastreia o número de segundos que passaram desde que o shell foi iniciado. Essa variável mantém suas propriedades quando atribuída a, e o valor retornado após a atribuição é o número de segundos desde a atribuição mais o valor atribuído.Assim, você pode simplesmente definir
SECONDS
como 0 antes de iniciar o evento cronometrado, simplesmente lerSECONDS
após o evento e fazer a aritmética da hora antes da exibição.Como essa solução não depende
date +%s
(que é uma extensão GNU), é portátil para todos os sistemas suportados pelo Bash.fonte
date
a execução da aritmética do tempo para você, escrevendodate -u -d @"$diff" +'%-Mm %-Ss'
. (Isso interpreta$diff
como segundos desde a época e calcula os minutos e segundos no UTC.) Isso provavelmente não é mais elegante, porém, apenas melhor ofuscado. :-Pecho "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
$(date -u +%s)
para evitar uma condição de corrida nas datas em que o horário de verão é alterado. E cuidado com os maus segundos de salto;)unset SECONDS
ela desaparecer:echo $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
Segundos
Para medir o tempo decorrido (em segundos), precisamos:
Um valor inteiro de segundos decorridos:
Existem duas maneiras internas do bash para encontrar um valor inteiro para o número de segundos decorridos:
Variável de bash SECONDS (se SECONDS estiver desativado, ele perde sua propriedade especial).
Configurando o valor de SECONDS para 0:
Armazenando o valor da variável
SECONDS
no início:Opção Bash printf
%(datefmt)T
:Converta esse número inteiro em um formato utilizável
O bash interno
printf
pode fazer isso diretamente:similarmente
mas isso falhará por durações de mais de 24 horas, pois na verdade imprimimos um tempo de relógio de parede, não exatamente uma duração:
Para os amantes dos detalhes, em bash-hackers.org :
Portanto, convém ligar para
textifyDuration $elpasedseconds
ondetextifyDuration
está mais uma implementação da impressão por duração:Data GNU.
Para obter um tempo formatado, devemos usar uma ferramenta externa (data GNU) de várias maneiras para atingir quase um ano e incluir nanossegundos.
Data interna da matemática.
Não há necessidade de aritmética externa, faça tudo em uma única etapa
date
:Sim, existe um
0
zero na cadeia de comando. É necessário.Isso pressupõe que você possa alterar o
date +"%T"
comando para umdate +"%s"
comando para que os valores sejam armazenados (impressos) em segundos.Observe que o comando está limitado a:
$StartDate
e$FinalDate
segundos.$FinalDate
é maior (mais tarde) que$StartDate
.Se você deve usar a
10:33:56
sequência, basta convertê-la em segundos,também, a palavra segundos pode ser abreviada como sec:
Observe que a conversão de segundos em tempo (como apresentada acima) é relativa ao início deste dia "hoje" (hoje).
O conceito pode ser estendido para nanossegundos, assim:
Se for necessário calcular diferenças de tempo mais longas (até 364 dias), devemos usar o início de (alguns) anos como referência e o valor do formato
%j
(o número do dia no ano):Igual a:
Infelizmente, nesse caso, precisamos subtrair manualmente
1
UM do número de dias. O comando date exibe o primeiro dia do ano como 1. Não é tão difícil ...O uso de um número longo de segundos é válido e documentado aqui:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
Data do Busybox
Uma ferramenta usada em dispositivos menores (um executável muito pequeno para instalar): Busybox.
Crie um link para o busybox chamado data:
Use-o e chame-o
date
(coloque-o em um diretório incluído no PATH).Ou crie um alias como:
A data do Busybox tem uma boa opção: -D para receber o formato do horário de entrada. Isso abre muitos formatos para serem usados com o tempo. Usando a opção -D, podemos converter o tempo 10:33:56 diretamente:
E como você pode ver na saída do comando acima, presume-se que o dia seja "hoje". Para começar o tempo na época:
A data do Busybox pode até receber a hora (no formato acima) sem -D:
E o formato de saída pode até demorar alguns segundos desde a época.
Nas duas vezes e um pouco de matemática bash (o busybox ainda não pode fazer as contas):
Ou formatado:
fonte
%(FORMAT)T
sequência passada para oprintf
comando integrado no bash. Em bash-hackers.org : imprima%(FORMAT)T
a string de data e hora resultante do usoFORMAT
como string de formato para strftime (3). O argumento associado é o número de segundos desde a Época, ou -1 (hora atual) ou -2 (hora de inicialização do shell). Se nenhum argumento correspondente for suprimento, o horário atual será usado como padrão . Isso é esotérico. Nesse caso,%s
como indicadostrftime(3)
é "o número de segundos desde a época".Aqui está como eu fiz isso:
Realmente simples, calcule o número de segundos no início, depois o número de segundos no final e imprima a diferença em minutos: segundos.
fonte
awk
neste caso, já que o Bash lida com aritmética inteira igualmente bem.awk
comandos para bash (se não for por mais nada, porque o awk funciona em outros shells). Gostei mais desta solução. Mas essa é a minha opinião pessoal.Outra opção é usar a
datediff
partir dedateutils
( http://www.fresse.org/dateutils/#datediff ):Você também pode usar
gawk
.mawk
1.3.4 também temstrftime
emktime
, mas versões mais antigas demawk
enawk
não fazer.Ou aqui está outra maneira de fazer isso com o GNU
date
:fonte
date
método GNU . Gênio.dateutils
via apt, não haviadatediff
comando - tinha que usardateutils.ddiff
.Eu gostaria de propor outra maneira que evite recuperar o
date
comando. Pode ser útil se você já tiver coletado registros de%T
data e hora no formato de data:podemos até lidar com milissegundos da mesma maneira.
fonte
echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s))))
trabalhou para mim desde que chegueivalue too great for base (error token is "08")
Aqui está um pouco de mágica:
sed
substitui a:
por uma fórmula para converter para 1/60. Em seguida, o cálculo do tempo feito porbc
fonte
A partir da data (GNU coreutils) 7.4, agora você pode usar -d para fazer aritmética:
As unidades que você pode usar são dias, anos, meses, horas, minutos e segundos:
fonte
Seguindo a resposta de Daniel Kamil Kozar, para mostrar horas / minutos / segundos:
Portanto, o script completo seria:
fonte
Ou embrulhe um pouco
Então isso funciona.
fonte
Aqui está uma solução usando apenas os
date
recursos de comandos usando "atrás" e não usando uma segunda variável para armazenar o tempo de término:isto dá:
fonte
fonte
date
.date
pode lhe dar a diferença e formatá-la para você (opções do OS X mostradas)Algum processamento de cadeia pode remover esses valores vazios
Isso não funcionará se você colocar o horário anterior primeiro. Se você precisar lidar com isso, mude
$(($(date ...) - $(date ...)))
para$(echo $(date ...) - $(date ...) | bc | tr -d -)
fonte
Eu precisava de um script de diferença de horário para usar com
mencoder
(--endpos
é relativo), e minha solução é chamar um script Python:frações de segundos também são suportadas:
e pode dizer que a diferença entre 200 e 120 é 1h 20m:
e pode converter qualquer número (provavelmente fracionário) de segundos ou minutos ou horas em hh: mm: ss
timediff.py:
fonte
Com o GNU
units
:fonte
Generalizando a solução do @ nisetama usando a data GNU (confiável Ubuntu 14.04 LTS):
produzindo:
fonte
fonte
Defina esta função (digamos em ~ / .bashrc):
Agora você pode medir o tempo de partes de seus scripts:
muito útil para encontrar gargalos de execução.
fonte
Sei que essa é uma postagem mais antiga, mas hoje a encontrei enquanto trabalhava em um script que usava datas e horas de um arquivo de log e calculava o delta. O script abaixo certamente é um exagero, e eu recomendo verificar minha lógica e matemática.
Você obterá a saída da seguinte maneira.
Modifiquei um pouco o script para torná-lo independente (ou seja, basta definir valores variáveis), mas talvez a ideia geral também seja apresentada. Você pode querer uma verificação de erro adicional para valores negativos.
fonte
Não posso comentar a resposta de mcaleaa, por isso posto aqui. A variável "diff" deve estar em minúsculas. Aqui está um exemplo.
A variável anterior foi declarada em minúscula. Foi o que aconteceu quando letras maiúsculas são usadas.
Então, a solução rápida seria assim
fonte
Aqui está minha implementação bash (com bits retirados de outros SO ;-)
Não testado, pode ser de buggy.
fonte