Eines der Argumente, die mein Skript erhält, ist ein Datum im folgenden Format : yyyymmdd
.
Ich möchte überprüfen, ob ich ein gültiges Datum als Eingabe erhalte.
Wie kann ich das machen? Ich versuche einen regulären Ausdruck wie:[0-9]\{\8}
Eines der Argumente, die mein Skript erhält, ist ein Datum im folgenden Format : yyyymmdd
.
Ich möchte überprüfen, ob ich ein gültiges Datum als Eingabe erhalte.
Wie kann ich das machen? Ich versuche einen regulären Ausdruck wie:[0-9]\{\8}
Antworten:
Sie können das Testkonstrukt [[ ]]
zusammen mit dem Übereinstimmungsoperator für reguläre Ausdrücke verwenden =~
, um zu überprüfen, ob eine Zeichenfolge mit einem Regex-Muster übereinstimmt.
Für Ihren speziellen Fall können Sie schreiben:
[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"
Oder genauer gesagt ein genauer Test:
[[ $date =~ ^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$ ]] && echo "yes"
# |^^^^^^^^ ^^^^^^ ^^^^^^ ^^^^^^ ^^^^^^^^^^ ^^^^^^ |
# | | ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ |
# | | | | |
# | | \ | |
# | --year-- --month-- --day-- |
# | either 01...09 either 01..09 end of line
# start of line or 10,11,12 or 10..29
# or 30, 31
Das heißt, Sie können in Bash einen regulären Ausdruck definieren, der dem gewünschten Format entspricht. So können Sie vorgehen:
[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"
Dabei werden Befehle nach &&
ausgeführt, wenn der Test erfolgreich ist, und Befehle nach ||
ausgeführt, wenn der Test nicht erfolgreich ist.
Beachten Sie, dass dies auf der Lösung von Aleks-Daniel Jakimenko in der Überprüfung des Datumsformats für Benutzereingaben in Bash basiert .
In anderen Shells können Sie grep verwenden . Wenn Ihre Shell POSIX-kompatibel ist, tun Sie dies
(echo "$date" | grep -Eq ^regex$) && echo "matched" || echo "did not match"
Bei Fischen , die nicht POSIX-konform sind, können Sie dies tun
echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"
grep
Befehle mit -E
Flag.
sh
, fish
oder andere weniger gut ausgestattete Muscheln.
In Bash Version 3 können Sie den Operator '= ~' verwenden:
if [[ "$date" =~ ^[0-9]{8}$ ]]; then
echo "Valid date"
else
echo "Invalid date"
fi
Referenz: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
HINWEIS: Das Anführungszeichen im Matching-Operator in den doppelten Klammern [[]] ist ab Bash Version 3.2 nicht mehr erforderlich
Eine gute Möglichkeit, um zu testen, ob eine Zeichenfolge ein korrektes Datum ist, besteht darin, das Befehlsdatum zu verwenden:
if date -d "${DATE}" >/dev/null 2>&1
then
# do what you need to do with your date
else
echo "${DATE} incorrect date" >&2
exit 1
fi
Aus Kommentar: Man kann die Formatierung verwenden
if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ]
date -d 2017-11-14e
es zum Beispiel mache, wird es am 14. November um 05:00:00 UTC 2017 zurückgegeben, aber das würde mein Skript beschädigen.
Ich würde expr match
anstelle von verwenden =~
:
expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes
Dies ist besser als die derzeit akzeptierte Antwort der Verwendung, =~
da =~
sie auch mit leeren Zeichenfolgen übereinstimmt, was meiner Meinung nach nicht der Fall sein sollte. Angenommen, es badvar
ist nicht definiert, dann [[ "1234" =~ "$badvar" ]]; echo $?
gibt es (falsch) 0
, während es expr match "1234" "$badvar" >/dev/null ; echo $?
das richtige Ergebnis gibt 1
.
Wir müssen den Ausgabewert>/dev/null
ausblenden expr match
, dh die Anzahl der übereinstimmenden Zeichen oder 0, wenn keine Übereinstimmung gefunden wurde. Beachten Sie, dass sich der Ausgabewert vom Exit-Status unterscheidet . Der Exit-Status ist 0, wenn eine Übereinstimmung gefunden wurde, oder 1, wenn dies nicht der Fall ist.
Im Allgemeinen expr
lautet die Syntax für :
expr match "$string" "$lead"
Oder:
expr "$string" : "$lead"
wo $lead
ist ein regulärer Ausdruck. Es exit status
ist wahr (0), wenn es lead
mit dem führenden Slice von string
(Gibt es einen Namen dafür?) Übereinstimmt . Zum Beispiel expr match "abcdefghi" "abc"
Exits true
, aber expr match "abcdefghi" "bcd"
Exits false
. (Dank an @Carlo Wood für den Hinweis.
=~
stimmt nicht mit leeren Zeichenfolgen überein, Sie vergleichen eine Zeichenfolge mit einem leeren Muster in dem von Ihnen angegebenen Beispiel. Die Syntax lautet string =~ pattern
und ein leeres Muster passt zu allem.
expr match "abcdefghi" "^" && echo Matched || echo No match
- und expr match "abcdefghi" "bcd" && echo Matched || echo No match
- kehren beide zurück "0\nNo match"
. Wo als Matching "a.*f"
wird zurückkehren "6\nMatched"
. Die Verwendung des '^' in Ihrem Beispiel ist daher ebenfalls unnötig und bereits impliziert.
=~
Abgleichen leerer Strings rationalisieren kann . Es ist so, dass dieses Verhalten unerwartet sein und Fehler verursachen kann. Ich habe diese Antwort speziell geschrieben, weil ich davon verbrannt wurde.
expr
stimmt der Autor von GNU mir zu.
Wenn die Verwendung eines regulären Ausdrucks hilfreich sein kann, um festzustellen, ob die Zeichenfolge eines Datums korrekt ist, kann sie nicht einfach verwendet werden, um festzustellen, ob das Datum gültig ist. Die folgenden Beispiele übergeben den regulären Ausdruck, sind jedoch alle ungültige Daten: 20180231, 20190229, 20190431
Wenn Sie also überprüfen möchten, ob Ihre Datumszeichenfolge (nennen wir sie datestr
) das richtige Format hat, ist es am besten, sie zu analysieren date
und date
die Zeichenfolge in das richtige Format zu konvertieren. Wenn beide Zeichenfolgen identisch sind, haben Sie ein gültiges Format und ein gültiges Datum.
if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
echo "Valid date"
else
echo "Invalid date"
fi