Проверьте, соответствует ли строка регулярному выражению в Bash script
Один из аргументов, который получает мой script, - это дата в следующем формате: yyyymmdd
.
Я хочу проверить, получаю ли я действительную дату в качестве ввода.
Как я могу это сделать? Я пытаюсь использовать регулярное выражение, например: [0-9]\{\8}
Ответы
Ответ 1
Ты можешь сказать:
[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"
Или точнее:
[[ $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
То есть вы можете определить регулярное выражение в bash, соответствующее желаемому формату. Таким образом, вы можете сделать:
[[ $date =~ ^regex$ ]] && echo "matched" || echo "did not match"
Обратите внимание, что это основано на решении Алекса-Даниэля Якименко, приведенном в разделе Проверка формата ввода данных пользователем в bash.
В других оболочках вы можете использовать grep. Если ваша оболочка совместима с POSIX, сделайте
(echo "$date" | grep -Eq ^regex$) && echo "matched" || echo "did not match"
В рыбе, которая не соответствует POSIX, вы можете сделать
echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"
Ответ 2
В версии bash версии 3 вы можете использовать оператор '= ~':
if [[ "$date" =~ "[0-9]\{8\}" ]]; then
echo "Valid date"
else
echo "Invalid date"
fi
Ссылка: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF
ПРИМЕЧАНИЕ. Цитирование в операторе сопоставления в двойных скобках, [[]], больше не требуется в отношении bash версии 3.2
Ответ 3
Хороший способ проверить, является ли строка правильной датой, использовать дату команды:
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
Ответ 4
Я бы использовал expr match
вместо =~
:
expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes
Это лучше, чем принятый в настоящее время ответ на использование =~
потому что =~
также будет соответствовать пустым строкам, что, по-моему, не должно. Предположим, что badvar
не определен, тогда [[ "1234" =~ "$badvar" ]]; echo $?
[[ "1234" =~ "$badvar" ]]; echo $?
дает (неверно) 0
, в то время как expr match "1234" "$badvar" >/dev/null; echo $?
expr match "1234" "$badvar" >/dev/null; echo $?
дает правильный результат 1
.
Мы должны использовать >/dev/null
чтобы скрыть выходное значение expr match
, которое представляет собой количество совпавших символов или 0, если совпадение не найдено. Обратите внимание, что его выходное значение отличается от его состояния выхода. Статус выхода равен 0, если совпадение найдено, или 1 в противном случае.
Как правило, синтаксис для expr
:
expr match "$string" "$lead"
Или же:
expr "$string" : "$lead"
где $lead
- это регулярное выражение. Его exit status
будет истинным (0), если lead
соответствует лидирующему фрагменту string
(есть имя для этого?). Например, expr match "abcdefghi" "abc"
выходит из true
, но expr match "abcdefghi" "bcd"
выходит из false
. (Благодарю @Carlo Wood за указание на это.
Ответ 5
В тех случаях, когда использование регулярного выражения может быть полезным для определения правильности последовательности символов даты, его нельзя легко определить, является ли дата действительной. Следующие примеры передают регулярное выражение, но все они являются недопустимыми датами: 20180231, 20190229, 20190431
Поэтому, если вы хотите проверить правильность формата строки даты (пусть назовет ее datestr
), лучше проанализировать ее с date
и запросить date
чтобы преобразовать строку в правильный формат. Если обе строки идентичны, у вас есть правильный формат и действительная дата.
if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
echo "Valid date"
else
echo "Invalid date"
fi