Jednym z argumentów, że mój skrypt otrzymuje to data w następującym formacie: yyyymmdd.
Chcę sprawdzić, czy otrzymam prawidłową datę jako dane wejściowe.
W jaki sposób mogę to zrobić? Próbuję użyć wyrażenia regularnego, takiego jak:[0-9]\{\8}
Jednym z argumentów, że mój skrypt otrzymuje to data w następującym formacie: yyyymmdd.
Chcę sprawdzić, czy otrzymam prawidłową datę jako dane wejściowe.
W jaki sposób mogę to zrobić? Próbuję użyć wyrażenia regularnego, takiego jak:[0-9]\{\8}
Odpowiedzi:
Możesz użyć konstrukcji testowej [[ ]]wraz z operatorem dopasowania wyrażeń regularnych =~, aby sprawdzić, czy łańcuch pasuje do wzorca wyrażenia regularnego.
W konkretnym przypadku możesz napisać:
[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"
Lub dokładniejszy 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
Oznacza to, że możesz zdefiniować wyrażenie regularne w Bash pasujące do żądanego formatu. W ten sposób możesz:
[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"
gdzie polecenia po &&są wykonywane, jeśli test się powiedzie, a polecenia po ||są wykonywane, jeśli test się nie powiedzie.
Zauważ, że jest to oparte na rozwiązaniu Aleksa-Daniela Jakimenko w weryfikacji formatu daty wejściowej użytkownika w bash .
W innych powłokach możesz użyć grep . Jeśli twoja powłoka jest zgodna z POSIX, zrób
(echo "$date" | grep -Eq ^regex$) && echo "matched" || echo "did not match"
W przypadku ryb , które nie są zgodne z POSIX, możesz to zrobić
echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"
greppolecenia z -Eflagą.
sh, fishlub innych mniej wyposażone muszle.
W wersji bash 3 możesz użyć operatora „= ~”:
if [[ "$date" =~ ^[0-9]{8}$ ]]; then
echo "Valid date"
else
echo "Invalid date"
fi
Odniesienie: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
UWAGA: Cytowanie w operatorze dopasowywania w podwójnych nawiasach [[]] nie jest już konieczne od wersji Bash 3.2
Dobrym sposobem sprawdzenia, czy ciąg znaków jest poprawną datą, jest użycie polecenia date:
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
z komentarza: można użyć formatowania
if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ]
date -d 2017-11-14eto zrobię , zwróci wtorek 14 listopada 05:00:00 UTC 2017, ale to zepsułoby mój skrypt.
Chciałbym użyć expr matchzamiast =~:
expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes
Jest to lepsze niż obecnie akceptowana odpowiedź na użycie, =~ponieważ =~dopasuje również puste ciągi, których IMHO nie powinno. Załóżmy, że badvarnie jest zdefiniowany, a następnie [[ "1234" =~ "$badvar" ]]; echo $?podaje (niepoprawnie) 0, a expr match "1234" "$badvar" >/dev/null ; echo $?daje poprawny wynik 1.
Musimy wykorzystać >/dev/nulldo ukrycia expr match„s wartości wyjściowej , która jest dopasowana liczba znaków lub 0 jeśli znaleziono żadnego meczu. Uwaga: jego wartość wyjściowa różni się od statusu wyjścia . Status wyjścia wynosi 0, jeśli znaleziono dopasowanie, lub 1 w innym przypadku.
Ogólnie rzecz biorąc, składnia dla expr:
expr match "$string" "$lead"
Lub:
expr "$string" : "$lead"
gdzie $leadjest wyrażenie regularne. To exit statusbędzie prawda (0), jeśli leadpasuje do wiodącego wycinka string(Czy istnieje na to nazwa?). Na przykład expr match "abcdefghi" "abc"wychodzi true, ale expr match "abcdefghi" "bcd"wychodzi false. (Podziękowania dla @Carlo Wood za zwrócenie na to uwagi.
=~nie pasuje do pustych ciągów, dopasowujesz ciąg do pustego wzorca w podanym przykładzie. Składnia jest string =~ pattern, a pusty wzorzec pasuje do wszystkiego.
expr match "abcdefghi" "^" && echo Matched || echo No match- i expr match "abcdefghi" "bcd" && echo Matched || echo No match- oba wracają "0\nNo match". Gdzie jako pasujące "a.*f"powróci "6\nMatched". Użycie „^” w twoim przykładzie jest zatem również niepotrzebne i już sugerowane.
=~pasujących pustych ciągów. Chodzi o to, że takie zachowanie może być nieoczekiwane i powodować błędy. Napisałem tę odpowiedź specjalnie dlatego, że ją spaliłem.
exprzgadza się ze mną.
Jeśli użycie wyrażenia regularnego może być pomocne w ustaleniu, czy sekwencja znaków daty jest poprawna, nie można go łatwo użyć do ustalenia, czy data jest poprawna. Poniższe przykłady przekażą wyrażenie regularne, ale wszystkie są niepoprawnymi datami: 20180231, 20190229, 20190431
Jeśli więc chcesz sprawdzić, czy ciąg daty (nazwijmy go datestr) ma poprawny format, najlepiej go przeanalizować datei poprosić dateo konwersję ciągu do właściwego formatu. Jeśli oba ciągi są identyczne, masz prawidłowy format i prawidłową datę.
if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
echo "Valid date"
else
echo "Invalid date"
fi