Comprobar si el formato es correcto es fácil. Pero no creo que pueda, en bash (con funciones integradas), verificar si la fecha es válida.
RedX
Respuestas:
317
Puede usar la construcción de prueba [[ ]], junto con el operador de coincidencia de expresiones regulares =~, para verificar si una cadena coincide con un patrón de expresiones regulares .
Para su caso específico, puede escribir:
[[ $date =~^[0-9]{8}$ ]]&& echo "yes"
O más una prueba precisa:
[[ $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
Es decir, puede definir una expresión regular en Bash que coincida con el formato que desee. De esta manera puedes hacer:
[[ $date =~^regex$ ]]&& echo "matched"|| echo "did not match"
donde los comandos posteriores &&se ejecutan si la prueba es exitosa, y los comandos posteriores ||se ejecutan si la prueba no tiene éxito.
Soy consciente de eso, pero también me gusta tener en cuenta quién pregunta y qué tan lejos están con bash. Si proporcionamos condiciones muy complejas, no aprenderán nada y simplemente regresarán cuando tengan otra duda. Prefiero dar una respuesta más comprensible.
Fedorqui 'SO deja de dañar'
77
Je Bueno, la única forma de aprender es leer mucho código bueno. Si proporciona un código falso que es fácil de entender pero que no se recomienda utilizar, es una mala forma de enseñar. También estoy bastante seguro de que para aquellos que acaban de comenzar a aprender bash (probablemente ya conozcan algunos bits de otro idioma) entenderán la sintaxis bash para expresiones regulares más fácilmente que algunos grepcomandos con -Eflag.
Aleks-Daniel Jakimenko-A.
8
@ Aleks-DanielJakimenko Revisé esta publicación nuevamente y ahora estoy de acuerdo en que es mejor usar bash regex. Gracias por apuntar en la buena dirección, respuesta actualizada.
Fedorqui 'SO deja de dañar'
44
Voto a favor, que permite usarlo un poco más allá de la pregunta OP, para sh, por ejemplo ...
Dereckson
3
@ Aleks-DanielJakimenko usando grep parece ser la mejor opción si usted está utilizando sh, fishu otros proyectiles menos equipados.
Califique su respuesta, ya que permite que la función de fecha se ocupe de las fechas y no de las expresiones regulares propensas a errores '
Ali
Esto es bueno para verificar las opciones de fecha amplia, pero si necesita verificar un formato de fecha específico, ¿puede hacerlo? Por ejemplo, si lo hago date -d 2017-11-14e, devuelve el martes 14 de noviembre a las 05:00:00 UTC de 2017, pero eso rompería mi script.
Josiah
1
Podría usar algo así: if ["2017-01-14" == $ (date -d "2017-01-14" '+% Y-% m-% d')] Comprueba si la fecha es correcta y verifique si el resultado es el mismo que sus datos ingresados. Por cierto, tenga mucho cuidado con el formato de fecha localizado (Mes-Día-Año vs. Día-Mes-Año, por ejemplo)
Django Janny
1
Podría no funcionar, dependiendo de su localidad. Las fechas con formato estadounidense que usan MM-DD-AAAA no funcionarán en ningún otro lugar del mundo, usando DD-MM-AAAA (Europa) o AAAA-MM-DD (algunos lugares en Asia)
Paul
@Paul, ¿qué puede no funcionar? Como está escrito en un comentario, uno puede usar las opciones de formato ...
Betlista
4
Yo usaría en expr matchlugar de =~:
expr match "$date""[0-9]\{8\}">/dev/null && echo yes
Esto es mejor que la respuesta actualmente aceptada de usar =~porque =~también coincidirá con cadenas vacías, lo que en mi humilde opinión no debería. Supongamos badvarque no está definido, luego [[ "1234" =~ "$badvar" ]]; echo $?da (incorrectamente) 0, mientras expr match "1234" "$badvar" >/dev/null ; echo $?da el resultado correcto 1.
Tenemos que usar >/dev/nullpara ocultar expr matchel valor de salida , que es el número de caracteres coincidentes o 0 si no se encuentra ninguna coincidencia. Tenga en cuenta que su valor de salida es diferente de su estado de salida . El estado de salida es 0 si se encuentra una coincidencia, o 1 en caso contrario.
En general, la sintaxis para expres:
expr match "$string""$lead"
O:
expr "$string":"$lead"
donde $leades una expresión regular Su exit statusserá cierto (0) si leadcoincide con el líder rebanada de string(¿Hay un nombre para esto?). Por ejemplo , expr match "abcdefghi" "abc"salidas true, pero expr match "abcdefghi" "bcd"salidas false. (Gracias a @Carlo Wood por señalar esto.
=~no coincide con cadenas vacías, está haciendo coincidir una cadena con un patrón vacío en el ejemplo que da La sintaxis es string =~ pattern, y un patrón vacío coincide con todo.
bstpierre
2
Esto no coincide con una subcadena, devuelve (a la salida estándar) el número de los principales personajes que hacía juego y el estado de salida es verdadera si y sólo si fue emparejado al menos 1 carácter. Es por eso que una cadena vacía (que coincide con 0 caracteres) tiene un estado de salida de falso. Por ejemplo expr match "abcdefghi" "^" && echo Matched || echo No match, y expr match "abcdefghi" "bcd" && echo Matched || echo No match- ambos regresan "0\nNo match". Donde como coincidencia "a.*f"volverá "6\nMatched". Por lo tanto, el uso de '^' en su ejemplo también es innecesario y ya está implícito.
Carlo Wood
@bstpierre: el punto aquí no es si uno puede racionalizar el comportamiento de =~combinar cadenas vacías. Es que este comportamiento puede ser inesperado y puede causar errores. Escribí esta respuesta específicamente porque me quemé.
Penghe Geng
@PengheGeng ¿Comportamiento inesperado? Si un patrón no tiene definición o restricciones, de hecho coincide con cualquier cosa. La ausencia de un patrón coincide con todo. Escribir un código robusto es la respuesta, no justifica una explicación pobre.
Anthony Rutledge
El "código robusto" de @AnthonyRutledge exige el mejor uso de las herramientas disponibles para evitar errores de codificación accidentales. En el código de Shell donde una variable vacía se puede introducir de manera fácil y accidental en cualquier momento por medio de errores ortográficos, no creo que permitir que las variables vacías coincidan es una característica sólida. Aparentemente, el autor de GNU exprestá de acuerdo conmigo.
Penghe Geng
0
Cuando el uso de una expresión regular puede ser útil para determinar si la secuencia de caracteres de una fecha es correcta, no se puede usar fácilmente para determinar si la fecha es válida. Los siguientes ejemplos pasarán la expresión regular, pero son todas las fechas inválidas: 20180231, 20190229, 20190431
Entonces, si desea validar si su cadena de fecha (llamémosla datestr) está en el formato correcto, es mejor analizarla datey solicitar dateconvertir la cadena al formato correcto. Si ambas cadenas son idénticas, tiene un formato válido y una fecha válida.
Respuestas:
Puede usar la construcción de prueba
[[ ]]
, junto con el operador de coincidencia de expresiones regulares=~
, para verificar si una cadena coincide con un patrón de expresiones regulares .Para su caso específico, puede escribir:
O más una prueba precisa:
Es decir, puede definir una expresión regular en Bash que coincida con el formato que desee. De esta manera puedes hacer:
donde los comandos posteriores
&&
se ejecutan si la prueba es exitosa, y los comandos posteriores||
se ejecutan si la prueba no tiene éxito.Tenga en cuenta que esto se basa en la solución de Aleks-Daniel Jakimenko en la verificación del formato de fecha de entrada del usuario en bash .
En otras conchas puedes usar grep . Si su shell es compatible con POSIX, haga
En pescado , que no es compatible con POSIX, puede hacer
fuente
grep
comandos con-E
flag.sh
,fish
u otros proyectiles menos equipados.En bash versión 3 puedes usar el operador '= ~':
Referencia: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
fuente
Una buena manera de probar si una cadena es una fecha correcta es usar el comando date:
del comentario: se puede usar el formato
fuente
date -d 2017-11-14e
, devuelve el martes 14 de noviembre a las 05:00:00 UTC de 2017, pero eso rompería mi script.Yo usaría en
expr match
lugar de=~
:Esto es mejor que la respuesta actualmente aceptada de usar
=~
porque=~
también coincidirá con cadenas vacías, lo que en mi humilde opinión no debería. Supongamosbadvar
que no está definido, luego[[ "1234" =~ "$badvar" ]]; echo $?
da (incorrectamente)0
, mientrasexpr match "1234" "$badvar" >/dev/null ; echo $?
da el resultado correcto1
.Tenemos que usar
>/dev/null
para ocultarexpr match
el valor de salida , que es el número de caracteres coincidentes o 0 si no se encuentra ninguna coincidencia. Tenga en cuenta que su valor de salida es diferente de su estado de salida . El estado de salida es 0 si se encuentra una coincidencia, o 1 en caso contrario.En general, la sintaxis para
expr
es:O:
donde
$lead
es una expresión regular Suexit status
será cierto (0) silead
coincide con el líder rebanada destring
(¿Hay un nombre para esto?). Por ejemplo ,expr match "abcdefghi" "abc"
salidastrue
, peroexpr match "abcdefghi" "bcd"
salidasfalse
. (Gracias a @Carlo Wood por señalar esto.fuente
=~
no coincide con cadenas vacías, está haciendo coincidir una cadena con un patrón vacío en el ejemplo que da La sintaxis esstring =~ pattern
, y un patrón vacío coincide con todo.expr match "abcdefghi" "^" && echo Matched || echo No match
, yexpr match "abcdefghi" "bcd" && echo Matched || echo No match
- ambos regresan"0\nNo match"
. Donde como coincidencia"a.*f"
volverá"6\nMatched"
. Por lo tanto, el uso de '^' en su ejemplo también es innecesario y ya está implícito.=~
combinar cadenas vacías. Es que este comportamiento puede ser inesperado y puede causar errores. Escribí esta respuesta específicamente porque me quemé.expr
está de acuerdo conmigo.Cuando el uso de una expresión regular puede ser útil para determinar si la secuencia de caracteres de una fecha es correcta, no se puede usar fácilmente para determinar si la fecha es válida. Los siguientes ejemplos pasarán la expresión regular, pero son todas las fechas inválidas: 20180231, 20190229, 20190431
Entonces, si desea validar si su cadena de fecha (llamémosla
datestr
) está en el formato correcto, es mejor analizarladate
y solicitardate
convertir la cadena al formato correcto. Si ambas cadenas son idénticas, tiene un formato válido y una fecha válida.fuente