Um dos argumentos que o meu script recebe é uma data no seguinte formato: yyyymmdd
.
Quero verificar se recebo uma data válida como entrada.
Como posso fazer isso? Estou tentando usar um regex como:[0-9]\{\8}
Um dos argumentos que o meu script recebe é uma data no seguinte formato: yyyymmdd
.
Quero verificar se recebo uma data válida como entrada.
Como posso fazer isso? Estou tentando usar um regex como:[0-9]\{\8}
Respostas:
Você pode usar a construção de teste [[ ]]
, juntamente com o operador de correspondência de expressão regular =~
, para verificar se uma sequência corresponde a um padrão de expressão regular .
Para o seu caso específico, você pode escrever:
[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"
Ou mais, um teste preciso:
[[ $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
Ou seja, você pode definir um regex no Bash que corresponda ao formato desejado. Desta forma, você pode fazer:
[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"
onde os comandos posteriores &&
são executados se o teste for bem-sucedido e os comandos posteriores ||
são executados se o teste for malsucedido.
Observe que isso se baseia na solução de Aleks-Daniel Jakimenko na verificação de formato de data de entrada do usuário no bash .
Em outros shells, você pode usar o grep . Se o seu shell for compatível com POSIX, faça
(echo "$date" | grep -Eq ^regex$) && echo "matched" || echo "did not match"
No peixe , que não é compatível com POSIX, você pode fazer
echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"
grep
comando com -E
flag.
sh
, fish
ou outras conchas menos equipados.
Na versão 3 do bash, você pode usar o operador '= ~':
if [[ "$date" =~ ^[0-9]{8}$ ]]; then
echo "Valid date"
else
echo "Invalid date"
fi
Referência: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
NOTA: A citação no operador correspondente entre colchetes duplos, [[]], não é mais necessária a partir do Bash versão 3.2
Uma boa maneira de testar se uma string é uma data correta é usar a data do 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
do comentário: pode-se usar a formatação
if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ]
date -d 2017-11-14e
ele retornará Ter 14 de novembro 05:00:00 UTC 2017, mas isso quebraria meu script.
Eu usaria em expr match
vez de =~
:
expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes
Isso é melhor do que a resposta de uso atualmente aceita, =~
porque =~
também corresponderá a cadeias vazias, o que IMHO não deveria. Suponha que badvar
não esteja definido, depois [[ "1234" =~ "$badvar" ]]; echo $?
dê (incorretamente) 0
, enquanto expr match "1234" "$badvar" >/dev/null ; echo $?
dá o resultado correto 1
.
Temos que usar >/dev/null
para ocultar expr match
o valor de saída , que é o número de caracteres correspondidos ou 0 se nenhuma correspondência for encontrada. Observe que seu valor de saída é diferente de seu status de saída . O status de saída é 0 se houver uma correspondência encontrada ou 1 caso contrário.
Geralmente, a sintaxe para expr
é:
expr match "$string" "$lead"
Ou:
expr "$string" : "$lead"
onde $lead
é uma expressão regular. Sua exit status
será verdadeiro (0) se lead
partidas a principal fatia de string
(há um nome para isso?). Por exemplo , expr match "abcdefghi" "abc"
sai true
, mas expr match "abcdefghi" "bcd"
sai false
. (Agradecemos a @Carlo Wood por apontar isso.
=~
não está combinando cadeias vazias, você está combinando uma cadeia com um padrão vazio no exemplo que você fornece. A sintaxe é string =~ pattern
e um padrão vazio corresponde a tudo.
expr match "abcdefghi" "^" && echo Matched || echo No match
- e expr match "abcdefghi" "bcd" && echo Matched || echo No match
- ambos retornam "0\nNo match"
. Onde a correspondência "a.*f"
retornará "6\nMatched"
. O uso do '^' no seu exemplo é, portanto, também desnecessário e já está implícito.
=~
combinar cadeias vazias. É que esse comportamento pode ser inesperado e pode causar erros. Escrevi esta resposta especificamente porque fui queimada por ela.
expr
concorda comigo.
Onde o uso de uma regex pode ser útil para determinar se a sequência de caracteres de uma data está correta, ela não pode ser usada facilmente para determinar se a data é válida. Os exemplos a seguir passarão a expressão regular, mas são todas datas inválidas: 20180231, 20190229, 20190431
Portanto, se você deseja validar se sua sequência de datas (vamos chamá-la datestr
) está no formato correto, é melhor analisá-la date
e pedir date
para converter a sequência no formato correto. Se as duas strings forem idênticas, você terá um formato e uma data válidos.
if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
echo "Valid date"
else
echo "Invalid date"
fi