Uno degli argomenti che il mio script riceve è una data nel seguente formato: yyyymmdd
.
Voglio verificare se ricevo una data valida come input.
Come posso fare questo? Sto cercando di usare un regex come:[0-9]\{\8}
Uno degli argomenti che il mio script riceve è una data nel seguente formato: yyyymmdd
.
Voglio verificare se ricevo una data valida come input.
Come posso fare questo? Sto cercando di usare un regex come:[0-9]\{\8}
Risposte:
È possibile utilizzare il costrutto test [[ ]]
, insieme all'operatore di corrispondenza delle espressioni regolari =~
, per verificare se una stringa corrisponde a un modello regex.
Per il tuo caso specifico, puoi scrivere:
[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"
O più un test accurato:
[[ $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
Cioè, puoi definire una regex in Bash corrispondente al formato desiderato. In questo modo puoi fare:
[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"
dove i comandi after &&
vengono eseguiti se il test ha esito positivo e i comandi after ||
vengono eseguiti se il test ha esito negativo.
Nota che questo si basa sulla soluzione di Aleks-Daniel Jakimenko nella verifica del formato della data di input dell'utente in bash .
In altre shell puoi usare grep . Se la tua shell è conforme POSIX, fallo
(echo "$date" | grep -Eq ^regex$) && echo "matched" || echo "did not match"
Nel pesce , che non è conforme a POSIX, puoi farlo
echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"
grep
comando con -E
flag.
sh
, fish
o altre shell meno equipaggiate.
Nella versione 3 di bash puoi usare l'operatore '= ~':
if [[ "$date" =~ ^[0-9]{8}$ ]]; then
echo "Valid date"
else
echo "Invalid date"
fi
Riferimento: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
NOTA: la quotazione nell'operatore corrispondente tra parentesi doppie, [[]], non è più necessaria dalla versione 3.2 di Bash
Un buon modo per verificare se una stringa è una data corretta è utilizzare la data del comando:
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
dal commento: si può usare la formattazione
if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ]
date -d 2017-11-14e
restituisce mar 14 nov 05:00:00 UTC 2017, ma ciò spezzerebbe il mio copione.
Vorrei usare expr match
invece di =~
:
expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes
Questo è meglio della risposta attualmente accettata sull'uso =~
perché =~
corrisponderà anche a stringhe vuote, che IMHO non dovrebbe. Supponiamo che badvar
non sia definito, quindi [[ "1234" =~ "$badvar" ]]; echo $?
fornisce (in modo errato) 0
, mentre expr match "1234" "$badvar" >/dev/null ; echo $?
fornisce un risultato corretto 1
.
Dobbiamo usare >/dev/null
per nascondere expr match
il valore di output , che è il numero di caratteri corrispondenti o 0 se non viene trovata alcuna corrispondenza. Si noti che il suo valore di uscita è diverso dal suo stato di uscita . Lo stato di uscita è 0 se viene trovata una corrispondenza o 1 altrimenti.
Generalmente, la sintassi per expr
è:
expr match "$string" "$lead"
O:
expr "$string" : "$lead"
dove $lead
è un'espressione regolare. La sua exit status
sarà vero (0) se lead
partite la fetta principale di string
(C'è un nome per questo?). Ad esempio , expr match "abcdefghi" "abc"
esce true
, ma expr match "abcdefghi" "bcd"
esce false
. (Ringraziamo @Carlo Wood per averlo sottolineato.
=~
non corrisponde a stringhe vuote, stai abbinando una stringa a un modello vuoto nell'esempio che dai. La sintassi è string =~ pattern
e un modello vuoto corrisponde a tutto.
expr match "abcdefghi" "^" && echo Matched || echo No match
- e expr match "abcdefghi" "bcd" && echo Matched || echo No match
- entrambi ritornano "0\nNo match"
. Dove "a.*f"
tornerà come corrispondenza "6\nMatched"
. L'uso del '^' nel tuo esempio è quindi anche superfluo e già implicito.
=~
corrispondenza di stringhe vuote. È che questo comportamento potrebbe essere inaspettato e causare errori. Ho scritto questa risposta proprio perché ne sono stata bruciata.
expr
accordo con me.
Laddove l'uso di una regex può essere utile per determinare se la sequenza di caratteri di una data è corretta, non può essere utilizzata facilmente per determinare se la data è valida. I seguenti esempi passeranno l'espressione regolare, ma sono tutte date non valide: 20180231, 20190229, 20190431
Quindi, se si desidera convalidare se la stringa della data (chiamiamola datestr
) è nel formato corretto, è meglio analizzarla date
e chiedere date
di convertire la stringa nel formato corretto. Se entrambe le stringhe sono identiche, hai un formato e una data validi.
if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
echo "Valid date"
else
echo "Invalid date"
fi