
Я пытаюсь получить двузначный месяц и двузначный год изменения файла, но это не работает...
modified=$(stat -c %y "$line");
# modified="2018-08-22 14:39:36.400469308 -0400"
if [[ $modified =~ ".{2}(\d{2})-(\d{2})" ]]; then
echo ${BASH_REMATCH[0]}
echo ${BASH_REMATCH[1]
fi
- Демонстрация Bash:http://rextester.com/DJSPH52792
- Демонстрация RegEx:https://regex101.com/r/UEOlMO/1
Что я делаю не так?
решение1
Во-первых, кавычки скрывают значение специальных символов в регулярном выражении (онлайн-руководство):
Доступен дополнительный бинарный оператор,
=~
... Любая часть шаблона может быть заключена в кавычки, чтобы принудительно сопоставить заключенную в кавычки часть как строку. ... Если вы хотите сопоставить символ, который является особым для грамматики регулярного выражения, его необходимо заключить в кавычки, чтобы удалить его особое значение.
Далее в руководстве рекомендуется поместить регулярное выражение в переменную, чтобы предотвратить некоторые конфликты между синтаксическим анализом оболочки и синтаксисом регулярного выражения.
Во-вторых, \d
не делает то, что вы думаете, а просто сопоставляется с литералом d
.
Также обратите внимание, что ${BASH_REMATCH[0]}
содержит всю совпадающую строку, а индексы 1
и выше содержат захваченные группы.
Я бы также настоятельно рекомендовал использовать четырехзначные обозначения года, поэтому:
modified=$(stat -c %y "$file")
re='^([0-9]{4})-([0-9]{2})'
if [[ $modified =~ $re ]]; then
echo "year: ${BASH_REMATCH[1]}"
echo "month: ${BASH_REMATCH[2]}"
else
echo "invalid timestamp"
fi
Для файла, измененного сегодня, это дает year: 2018
и month: 08
. Обратите внимание, что числа с начальным нулем будут считаться оболочкой и, возможно, другими утилитами восьмеричными.
(С четырехзначным обозначением года возникает меньше проблем, если вам когда-либо понадобится работать с датами 1900-х годов, и их легче распознать как годы, а не дни месяца.)
решение2
Для этого не нужны регулярные выражения:
$ touch -t 197001010000 myfile
$ ls -l myfile
-rw-rw-r-- 1 jackman jackman 0 Jan 1 1970 myfile
$ IFS='-' read -r year month _rest < <(stat -c %y myfile)
$ echo "$year:${year#??}"$month"
1970:70:01
решение3
В качестве альтернативы с помощью GNU date
вы можете сделать:
eval "$(date -r "$file" +'year=%Y month=%-m day=%-d')"
Чтобы сохранить компоненты года, месяца и дня времени изменения в $year
, $month
и $day
соответственно (в виде десятичных целых чисел, удалите -
s в %-m
и , %-d
если вас интересуют начальные нули; см. также %y
для двузначных годов).
(обратите внимание, что в отличие от GNU stat
, для файлов типа symlink учитывается время модификации цели символической ссылки, а не самой символической ссылки. При использовании GNU stat
вы бы использовали stat -L
).