it-swarm.com.de

Wie vergleiche ich zwei Daten in einer Shell?

Wie können zwei Daten in einer Shell verglichen werden?

Hier ist ein Beispiel, wie ich dies verwenden möchte, obwohl es nicht so funktioniert, wie es ist:

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

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

Wie kann ich das gewünschte Ergebnis erzielen?

95
Abdul

Die richtige Antwort fehlt noch:

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

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

Beachten Sie, dass hierfür GNU Datum) erforderlich ist. Die entsprechende date -Syntax für BSD date (wie standardmäßig in OSX zu finden) lautet date -j -f "%F" 2014-08-19 +"%s"

122
user93501

Kann einen Standard-Zeichenfolgenvergleich verwenden, um die chronologische Reihenfolge [von Zeichenfolgen im Format Jahr, Monat, Tag] zu vergleichen.

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

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

Zum Glück werden [Zeichenfolgen, die das Format JJJJ-MM-TT verwenden] * in alphabetischer Reihenfolge * auch in chronologischer Reihenfolge sortiert.

(* - sortiert oder verglichen)

In diesem Fall ist nichts Besonderes erforderlich. Yay!

36
user2533809

Ihnen fehlt das Datumsformat für den Vergleich:

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

Sie vermissen auch Schleifenstrukturen. Wie planen Sie, mehr Daten zu erhalten?

32
LPoblet

Dies ist kein Problem von Schleifenstrukturen, sondern von Datentypen.

Diese Daten (todate und cond) sind Zeichenfolgen, keine Zahlen, daher können Sie den Operator "-ge" von test nicht verwenden. (Denken Sie daran, dass die eckige Klammer dem Befehl test entspricht.)

Sie können für Ihre Daten eine andere Notation verwenden, sodass es sich um Ganzzahlen handelt. Zum Beispiel:

date +%Y%m%d

wird eine Ganzzahl wie 20130715 für den 15. Juli 2013 erzeugen. Dann können Sie Ihre Daten mit "-ge" und äquivalenten Operatoren vergleichen.

pdate : Wenn Ihre Daten angegeben sind (z. B. wenn Sie sie aus einer Datei im Format 2013-07-13 lesen), können Sie sie einfach mit tr vorverarbeiten.

$ echo "2013-07-15" | tr -d "-"
20130715
8
sergut

Der Operator -ge Arbeitet nur mit ganzen Zahlen, die Ihre Daten nicht sind.

Wenn es sich bei Ihrem Skript um ein Bash- oder Ksh- oder Zsh-Skript handelt, können Sie stattdessen den Operator < Verwenden. Dieser Operator ist nicht in Dash- oder anderen Shells verfügbar, die nicht viel über den POSIX-Standard hinausgehen.

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

In jeder Shell können Sie die Zeichenfolgen unter Einhaltung der Datumsreihenfolge in Zahlen konvertieren, indem Sie einfach die Bindestriche entfernen.

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

Alternativ können Sie auch traditionell das Dienstprogramm expr verwenden.

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

Da das Aufrufen von Unterprozessen in einer Schleife langsam sein kann, ziehen Sie es möglicherweise vor, die Transformation mithilfe von Shell-String-Verarbeitungskonstrukten durchzuführen.

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

Wenn Sie die Daten überhaupt ohne Bindestriche abrufen können, können Sie sie natürlich mit -ge Vergleichen.

Ich konvertiere die Strings in Unix-Zeitstempel (Sekunden seit 1.1.1970 0: 0: 0). Diese können leicht verglichen werden

unix_todate=$(date -d "${todate}" "+%s")
unix_cond=$(date -d "${cond}" "+%s")
if [ ${unix_todate} -ge ${unix_cond} ]; then
   echo "over condition"
fi
1
InuSasha

bash spezifische Antwort

Da ich Gabeln gerne reduziere und bash viele Tricks zulasse, gibt es meinen Zweck:

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

Na dann:

{ read todate; read cond ;} < <(date -f - +%s <<<"$todate"$'\n'"$cond")

Dadurch werden beide Variablen $todate Und $cond Mit nur einer Gabel neu ausgefüllt, wobei date -f - Ausgegeben wird, was stdio zum Lesen einer Variablen benötigt Datum nach Zeile.

Schließlich könnten Sie Ihre Schleife mit brechen

((todate>=cond))&&break

Oder als Funktion:

myfunc() {
    local todate cond
    { read todate
      read cond
    } < <(
      date -f - +%s <<<"$1"$'\n'"$2"
    )
    ((todate>=cond))&&return
    printf "%(%a %d %b %Y)T older than %(%a %d %b %Y)T...\n" $todate $cond
}

Verwenden Sie bash 's eingebautes printf, das die Datums- und Uhrzeitangabe mit Sekunden aus der Epoche (siehe man bash ;-) rendern könnte.

Dieses Skript verwendet nur eine Gabel.

Alternative mit eingeschränkten Gabeln und Datumsleserfunktion

Dadurch wird ein dedizierter Unterprozess erstellt (nur eine Gabelung):

mkfifo /tmp/fifo
exec 99> >(exec stdbuf -i 0 -o 0 date -f - +%s >/tmp/fifo 2>&1)
exec 98</tmp/fifo
rm /tmp/fifo

Da Eingabe und Ausgabe geöffnet sind, kann der FIFO-Eintrag gelöscht werden.

Die Funktion:

myDate() {
    local var="${@:$#}"
    shift
    echo >&99 "${@:1:$#-1}"
    read -t .01 -u 98 $var
}

Nota Um nutzlose Gabeln wie todate=$(myDate 2013-07-18) zu vermeiden, muss die Variable von der Funktion selbst gesetzt werden. Und um eine freie Syntax (mit oder ohne Anführungszeichen für den Datenring) zu ermöglichen, muss der Variablenname das letzte Argument sein.

Dann Datumsvergleich:

myDate 2013-07-18        todate
myDate Mon Jul 15 2013   cond
(( todate >= cond )) && {
    printf "To: %(%c)T > Cond: %(%c)T\n" $todate $cond
    break
}

kann rendern:

To: Thu Jul 18 00:00:00 2013 > Cond: Mon Jul 15 00:00:00 2013
bash: break: only meaningful in a `for', `while', or `until' loop

wenn außerhalb einer Schleife.

Oder verwenden Sie die Shell-Connector-Bash-Funktion:

wget https://github.com/F-Hauri/Connector-bash/raw/master/Shell_connector.bash

oder

wget https://f-hauri.ch/vrac/Shell_connector.sh

(Was nicht genau gleich ist: .sh Enthält ein vollständiges Testskript, wenn es nicht bezogen wurde)

source Shell_connector.sh
newConnector /bin/date '-f - +%s' @0 0

myDate 2013-07-18        todate
myDate "Mon Jul 15 2013"   cond
(( todate >= cond )) && {
    printf "To: %(%c)T > Cond: %(%c)T\n" $todate $cond
    break
}
1
F. Hauri

Es gibt auch diese Methode aus dem Artikel mit dem Titel: Einfache Datums- und Zeitberechnung in BASH von unix.com.

Diese Funktionen sind ein Auszug aus einem Skript in diesem Thread!

date2stamp () {
    date --utc --date "$1" +%s
}

dateDiff (){
    case $1 in
        -s)   sec=1;      shift;;
        -m)   sec=60;     shift;;
        -h)   sec=3600;   shift;;
        -d)   sec=86400;  shift;;
        *)    sec=86400;;
    esac
    dte1=$(date2stamp $1)
    dte2=$(date2stamp $2)
    diffSec=$((dte2-dte1))
    if ((diffSec < 0)); then abs=-1; else abs=1; fi
    echo $((diffSec/sec*abs))
}

Verwendungszweck

# calculate the number of days between 2 dates
    # -s in sec. | -m in min. | -h in hours  | -d in days (default)
    dateDiff -s "2006-10-01" "2006-10-31"
    dateDiff -m "2006-10-01" "2006-10-31"
    dateDiff -h "2006-10-01" "2006-10-31"
    dateDiff -d "2006-10-01" "2006-10-31"
    dateDiff  "2006-10-01" "2006-10-31"
1
slm

Die folgende @ Gilles-Antwort ("Der Operator -ge funktioniert nur mit ganzen Zahlen") ist ein Beispiel.

curr_date=$(date +'%Y-%m-%d')
echo "$curr_date"
2019-06-20

old_date="2019-06-19"
echo "$old_date"
2019-06-19

datetime Ganzzahlkonvertierungen in Epoch gemäß der Antwort von @ mike-q unter https://stackoverflow.com/questions/10990949/convert-date-time-string-to-Epoch -in-bash :

curr_date_int=$(date -d "${curr_date}" +"%s")
echo "$curr_date_int"
1561014000

old_date_int=$(date -d "${old_date}" +"%s")
echo "$old_date_int"
1560927600

"$curr_date" ist größer als (neuer als) "$old_date", aber dieser Ausdruck wird fälschlicherweise als False ausgewertet:

if [[ "$curr_date" -ge "$old_date" ]]; then echo 'foo'; fi

... hier explizit gezeigt:

if [[ "$curr_date" -ge "$old_date" ]]; then echo 'foo'; else echo 'bar'; fi
bar

Ganzzahlige Vergleiche:

if [[ "$curr_date_int" -ge "$old_date_int" ]]; then echo 'foo'; fi
foo

if [[ "$curr_date_int" -gt "$old_date_int" ]]; then echo 'foo'; fi
foo

if [[ "$curr_date_int" -lt "$old_date_int" ]]; then echo 'foo'; fi

if [[ "$curr_date_int" -lt "$old_date_int" ]]; then echo 'foo'; else echo 'bar'; fi
bar
0
Victoria Stuart

Sie können auch die integrierte Funktion von mysql verwenden, um die Daten zu vergleichen. Es gibt das Ergebnis in "Tagen".

from_date="2015-01-02"
date_today="2015-03-10"
diff=$(mysql -u${DBUSER} -p${DBPASSWORD} -N -e"SELECT DATEDIFF('${date_today}','${from_date}');")

Fügen Sie einfach die Werte von $DBUSER und $DBPASSWORD Variablen nach Ihren Wünschen.

0
Abid Khan

datumsangaben sind Zeichenfolgen, keine Ganzzahlen. Sie können sie nicht mit Standardarithmetikoperatoren vergleichen.

ein Ansatz, den Sie verwenden können, wenn das Trennzeichen garantiert - ist:

IFS=-
read -ra todate <<<"$todate"
read -ra cond <<<"$cond"
for ((idx=0;idx<=numfields;idx++)); do
  (( todate[idx] > cond[idx] )) && break
done
unset IFS

Dies funktioniert bereits bei bash 2.05b.0(1)-release.

0
Josh McGee

Der Grund, warum dieser Vergleich mit einer Datumszeichenfolge mit Bindestrich nicht gut funktioniert, ist, dass die Shell davon ausgeht, dass eine Zahl mit einer führenden 0 ein Oktal ist, in diesem Fall der Monat "07". Es wurden verschiedene Lösungen vorgeschlagen, aber die schnellste und einfachste besteht darin, die Bindestriche zu entfernen. Bash verfügt über eine Funktion zum Ersetzen von Zeichenfolgen, die dies schnell und einfach macht. Dann kann der Vergleich als arithmetischer Ausdruck durchgeführt werden:

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

if (( ${todate//-/} > ${cond//-/} ));
then
    echo larger
fi
0
John McNulty

FWIW: Auf dem Mac wird anscheinend nur ein Datum wie "2017-05-05" in das Datum eingegeben, um die aktuelle Uhrzeit an das Datum anzuhängen, und Sie erhalten jedes Mal einen anderen Wert, wenn Sie es in die Epochenzeit konvertieren. Um eine konsistentere Epochenzeit für feste Daten zu erhalten, geben Sie Dummy-Werte für Stunden, Minuten und Sekunden an:

date -j -f "%Y-%m-%d %H:%M:%S" "2017-05-05 00:00:00" +"%s"

Dies kann eine Kuriosität sein, die auf die Version des Datums beschränkt ist, das mit macOS ausgeliefert wurde .... getestet unter macOS 10.12.6.

0
s84