Il est facile de vérifier si le format est correct. Mais je ne pense pas que vous puissiez, en bash (avec les intégrés), vérifier si la date est valide.
RedX
Réponses:
317
Vous pouvez utiliser la construction de test, [[ ]]avec l'opérateur de correspondance d'expressions régulières =~, pour vérifier si une chaîne correspond à un modèle d' expression régulière .
Pour votre cas spécifique, vous pouvez écrire:
[[ $date =~^[0-9]{8}$ ]]&& echo "yes"
Ou un test plus précis:
[[ $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
Autrement dit, vous pouvez définir une expression régulière dans Bash correspondant au format souhaité. De cette façon, vous pouvez faire:
[[ $date =~^regex$ ]]&& echo "matched"|| echo "did not match"
où les commandes après &&sont exécutées si le test réussit et les commandes après ||sont exécutées si le test échoue.
J'en suis conscient, mais j'aime aussi prendre en compte qui demande et jusqu'où ils en sont avec bash. Si nous fournissons des conditions très complexes, ils n'apprendront rien et reviendront chaque fois qu'ils auront un autre doute. Je préfère donner une réponse plus compréhensible.
fedorqui 'SO arrête de nuire'
7
Il h. Eh bien, la seule façon d'apprendre est de lire beaucoup de bon code. Si vous donnez du faux code qui est facile à comprendre mais dont l'utilisation n'est pas recommandée, c'est une mauvaise façon d'enseigner. De plus, je suis presque sûr que pour ceux qui viennent de commencer à apprendre bash (connaissant probablement déjà quelques bribes d'une autre langue), ils comprendront la syntaxe bash pour regex plus facilement qu'une grepcommande avec -Eindicateur.
Aleks-Daniel Jakimenko-A.
8
@ Aleks-DanielJakimenko J'ai relu ce post et maintenant je suis d'accord qu'il vaut mieux utiliser bash regex. Merci d'avoir pointé dans la bonne direction, réponse mise à jour.
fedorqui 'SO arrête de nuire'
4
Upvote, qui permet de l'utiliser un peu au-delà de la question OP, pour sh, par exemple ..
Dereckson
3
@ Aleks-DanielJakimenko utilisant grep semble être la meilleure option si vous utilisez sh, fishou d'autres obus moins équipés.
tomekwi
47
Dans la version bash 3, vous pouvez utiliser l'opérateur '= ~':
Donnez une note élevée à votre réponse car elle permet à la fonction de date de traiter les dates et non les expressions rationnelles sujettes aux erreurs '
Ali
C'est bon pour vérifier les options de date générales, mais si vous devez vérifier un format de date spécifique, peut-il le faire? Par exemple, si je le fais, date -d 2017-11-14eil renvoie le 14 novembre 05:00:00 UTC 2017, mais cela casserait mon script.
Josiah
1
Vous pouvez utiliser quelque chose comme ça: if ["2017-01-14" == $ (date -d "2017-01-14" '+% Y-% m-% d')] Il teste si la date est correcte et vérifiez si le résultat est le même que vos données saisies. Au fait, soyez très prudent avec le format de date localisé (Mois-Jour-Année vs Jour-Mois-Année par exemple)
Django Janny
1
Pourrait ne pas fonctionner, selon votre région. Les dates au format américain utilisant MM-DD-YYYY ne fonctionneront nulle part ailleurs dans le monde, en utilisant soit DD-MM-YYYY (Europe) ou YYYY-MM-DD (certains endroits en Asie)
Paul
@Paul, qu'est-ce qui peut ne pas fonctionner? Comme écrit dans un commentaire, on peut utiliser des options de formatage ...
Betlista
4
J'utiliserais expr matchau lieu de =~:
expr match "$date""[0-9]\{8\}">/dev/null && echo yes
C'est mieux que la réponse actuellement acceptée, =~car =~elle correspondra également à des chaînes vides, ce qui à mon humble avis ne devrait pas. Supposons que badvarn'est pas défini, puis [[ "1234" =~ "$badvar" ]]; echo $?donne (incorrectement) 0, tandis que expr match "1234" "$badvar" >/dev/null ; echo $?donne un résultat correct1 .
Nous devons utiliser >/dev/nullpour masquer expr matchla valeur de sortie de , qui est le nombre de caractères correspondants ou 0 si aucune correspondance n'a été trouvée. Notez que sa valeur de sortie est différente de son état de sortie . Le statut de sortie est 0 si une correspondance est trouvée, ou 1 sinon.
Généralement, la syntaxe de exprest:
expr match "$string""$lead"
Ou:
expr "$string":"$lead"
où $leadest une expression régulière. Ce exit statussera vrai (0) si leadcorrespond à la tranche principale de string(Y a-t-il un nom pour cela?). Par exemple, expr match "abcdefghi" "abc"quitte true, mais expr match "abcdefghi" "bcd"quitte false. (Nous remercions @Carlo Wood de l'avoir signalé.
=~ne correspond pas à des chaînes vides, vous comparez une chaîne à un modèle vide dans l'exemple que vous donnez. La syntaxe est string =~ pattern, et un modèle vide correspond à tout.
bstpierre
2
Cela ne correspond pas à une sous-chaîne, il renvoie (à stdout) le nombre de caractères de tête qui correspondent et le statut de sortie est vrai si au moins 1 caractère a été trouvé. C'est pourquoi une chaîne vide (qui correspond à 0 caractère) a un statut de sortie faux. Par exemple expr match "abcdefghi" "^" && echo Matched || echo No match- et expr match "abcdefghi" "bcd" && echo Matched || echo No match- les deux reviennent "0\nNo match". Où que l'appariement "a.*f"reviendra "6\nMatched". L'utilisation du '^' dans votre exemple est donc également inutile et déjà implicite.
Carlo Wood
@bstpierre: il ne s'agit pas ici de savoir si l'on peut rationaliser le comportement de =~correspondance de chaînes vides. C'est que ce comportement peut être inattendu et provoquer des erreurs. J'ai écrit cette réponse précisément parce que j'ai été brûlé par elle.
Penghe Geng
@PengheGeng Comportement inattendu? Si un modèle n'a pas de définition ni de contraintes, il correspond en fait à n'importe quoi. L'absence de motif correspond à tout. Écrire du code robuste est la réponse, ne justifiant pas une mauvaise explication.
Anthony Rutledge
@AnthonyRutledge "code robuste" exige la meilleure utilisation des outils disponibles pour éviter les erreurs de codage accidentelles. Dans le code Shell où une variable vide peut être facilement et accidentellement introduite à tout moment par des erreurs d'orthographe, je ne pense pas que permettre la correspondance de variables vides soit une fonctionnalité robuste. Apparemment, l'auteur de GNU exprest d'accord avec moi.
Penghe Geng
0
Lorsque l'utilisation d'une expression régulière peut être utile pour déterminer si la séquence de caractères d'une date est correcte, elle ne peut pas être utilisée facilement pour déterminer si la date est valide. Les exemples suivants transmettront l'expression régulière, mais sont toutes des dates non valides: 20180231, 20190229, 20190431
Donc, si vous voulez valider si votre chaîne de date (appelons-la datestr) est au format correct, il est préférable de l'analyser avec dateet de demander dateà convertir la chaîne au format correct. Si les deux chaînes sont identiques, vous avez un format et une date valides.
Réponses:
Vous pouvez utiliser la construction de test,
[[ ]]
avec l'opérateur de correspondance d'expressions régulières=~
, pour vérifier si une chaîne correspond à un modèle d' expression régulière .Pour votre cas spécifique, vous pouvez écrire:
Ou un test plus précis:
Autrement dit, vous pouvez définir une expression régulière dans Bash correspondant au format souhaité. De cette façon, vous pouvez faire:
où les commandes après
&&
sont exécutées si le test réussit et les commandes après||
sont exécutées si le test échoue.Notez que cela est basé sur la solution d'Aleks-Daniel Jakimenko dans la vérification du format de date d'entrée utilisateur dans bash .
Dans d'autres shells, vous pouvez utiliser grep . Si votre shell est compatible POSIX, faites
Dans le poisson , qui n'est pas conforme à POSIX, vous pouvez faire
la source
grep
commande avec-E
indicateur.sh
,fish
ou d'autres obus moins équipés.Dans la version bash 3, vous pouvez utiliser l'opérateur '= ~':
Référence: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
la source
Un bon moyen de tester si une chaîne est une date correcte est d'utiliser la commande date:
du commentaire: on peut utiliser la mise en forme
la source
date -d 2017-11-14e
il renvoie le 14 novembre 05:00:00 UTC 2017, mais cela casserait mon script.J'utiliserais
expr match
au lieu de=~
:C'est mieux que la réponse actuellement acceptée,
=~
car=~
elle correspondra également à des chaînes vides, ce qui à mon humble avis ne devrait pas. Supposons quebadvar
n'est pas défini, puis[[ "1234" =~ "$badvar" ]]; echo $?
donne (incorrectement)0
, tandis queexpr match "1234" "$badvar" >/dev/null ; echo $?
donne un résultat correct1
.Nous devons utiliser
>/dev/null
pour masquerexpr match
la valeur de sortie de , qui est le nombre de caractères correspondants ou 0 si aucune correspondance n'a été trouvée. Notez que sa valeur de sortie est différente de son état de sortie . Le statut de sortie est 0 si une correspondance est trouvée, ou 1 sinon.Généralement, la syntaxe de
expr
est:Ou:
où
$lead
est une expression régulière. Ceexit status
sera vrai (0) silead
correspond à la tranche principale destring
(Y a-t-il un nom pour cela?). Par exemple,expr match "abcdefghi" "abc"
quittetrue
, maisexpr match "abcdefghi" "bcd"
quittefalse
. (Nous remercions @Carlo Wood de l'avoir signalé.la source
=~
ne correspond pas à des chaînes vides, vous comparez une chaîne à un modèle vide dans l'exemple que vous donnez. La syntaxe eststring =~ pattern
, et un modèle vide correspond à tout.expr match "abcdefghi" "^" && echo Matched || echo No match
- etexpr match "abcdefghi" "bcd" && echo Matched || echo No match
- les deux reviennent"0\nNo match"
. Où que l'appariement"a.*f"
reviendra"6\nMatched"
. L'utilisation du '^' dans votre exemple est donc également inutile et déjà implicite.=~
correspondance de chaînes vides. C'est que ce comportement peut être inattendu et provoquer des erreurs. J'ai écrit cette réponse précisément parce que j'ai été brûlé par elle.expr
est d'accord avec moi.Lorsque l'utilisation d'une expression régulière peut être utile pour déterminer si la séquence de caractères d'une date est correcte, elle ne peut pas être utilisée facilement pour déterminer si la date est valide. Les exemples suivants transmettront l'expression régulière, mais sont toutes des dates non valides: 20180231, 20190229, 20190431
Donc, si vous voulez valider si votre chaîne de date (appelons-la
datestr
) est au format correct, il est préférable de l'analyser avecdate
et de demanderdate
à convertir la chaîne au format correct. Si les deux chaînes sont identiques, vous avez un format et une date valides.la source