BASH не любит мое регулярное выражение

BASH не любит мое регулярное выражение

Я пытаюсь получить двузначный месяц и двузначный год изменения файла, но это не работает...

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

Что я делаю не так?

решение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).

Связанный контент