Como comparar duas datas em um shell?

Como comparar duas datas em um shell?

Como duas datas podem ser comparadas em um shell?

Aqui está um exemplo de como eu gostaria de usar isso, embora não funcione como está:

todate=2013-07-18
cond=2013-07-15

if [ $todate -ge $cond ];
then
    break
fi                           

Como posso alcançar o resultado desejado?

Responder1

A resposta certa ainda está faltando:

todate=$(date -d 2013-07-18 +%s)
cond=$(date -d 2014-08-19 +%s)

if [ $todate -ge $cond ];
then
    break
fi  

Observe que isso requer data GNU. A sintaxe equivalente datepara BSD date(como encontrada no OSX por padrão) édate -j -f "%F" 2014-08-19 +"%s"

Responder2

Pode usar uma comparação de strings no estilo ksh para comparar a ordem cronológica [de strings em formato de ano, mês, dia].

date_a=2013-07-18
date_b=2013-07-15

if [[ "$date_a" > "$date_b" ]] ;
then
    echo "break"
fi

Felizmente, quando [strings que usam o formato AAAA-MM-DD] são classificadas* em ordem alfabética, elas também são classificadas* em ordem cronológica.

(* - classificado ou comparado)

Nada sofisticado é necessário neste caso. yay!

Responder3

Está faltando o formato de data para a comparação:

#!/bin/bash

todate=$(date -d 2013-07-18 +"%Y%m%d")  # = 20130718
cond=$(date -d 2013-07-15 +"%Y%m%d")    # = 20130715

if [ $todate -ge $cond ]; #put the loop where you need it
then
 echo 'yes';
fi

Você também está sentindo falta de estruturas de loop. Como planeja conseguir mais datas?

Responder4

O operador -gesó funciona com números inteiros, o que não acontece com suas datas.

Se o seu script for um script bash ou ksh ou zsh, você poderá usar o <operador. Este operador não está disponível no dash ou em outros shells que não vão muito além do padrão POSIX.

if [[ $cond < $todate ]]; then break; fi

Em qualquer shell, você pode converter as strings em números respeitando a ordem das datas simplesmente removendo os travessões.

if [ "$(echo "$todate" | tr -d -)" -ge "$(echo "$cond" | tr -d -)" ]; then break; fi

Alternativamente, você pode usar o tradicional e usar o exprutilitário.

if expr "$todate" ">=" "$cond" > /dev/null; then break; fi

Como a invocação de subprocessos em um loop pode ser lenta, você pode preferir fazer a transformação usando construções de processamento de string de shell.

todate_num=${todate%%-*}${todate#*-}; todate_num=${todate_num%%-*}${todate_num#*-}
cond_num=${cond%%-*}${cond#*-}; cond_num=${cond_num%%-*}${cond_num#*-}
if [ "$todate_num" -ge "$cond_num" ]; then break; fi

Obviamente, se você puder recuperar as datas sem os hífens, poderá compará-las com -ge.

informação relacionada