как определить дату utc с помощью регулярного выражения в оболочке

#regex #grep

Вопрос:

Привет, кто-нибудь может подсказать, как настроить дату и время UTC в Linux?

Я пытаюсь использовать приведенный ниже синтаксис, но он не работает.

 utcdate=$(grep 'd{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2]d|3[0-1])T(?:[0-1]d|2[0-3]):[0-5]d:[0-5]dZ' filename)
 

формат даты : 2021-06-22T16:15:23Z

Комментарии:

1. grep не (обычно) понимает d .

2. utcdate=$(grep -oP 'd{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2]d|3[0-1])T(?:[0-1]d|2[0-3]):[0-5]d:[0-5]dZ' filename | head -1)

3. Пожалуйста, поделитесь образцами входных данных и ожидаемых результатов в своем вопросе, чтобы сделать его более понятным, спасибо.

4. @kirank : Вы проинструктировали grep использовать базовые регулярные выражения . Если вы сделаете это, вам придется ограничиться этим. См. раздел » Выбор соответствия» на справочной странице grep.

5. Чтобы придраться: это не дата «UTC», это стандартный формат даты и времени ISO 8601: en.wikipedia.org/wiki/ISO_8601

Ответ №1:

Самое простое решение-добавить -oP опции и добавить | head -1 в шаблон:

 utcdate=$(grep -oP 'd{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2]d|3[0-1])T(?:[0-1]d|2[0-3]):[0-5]d:[0-5]dZ' filename | head -1)
 

o Опция выведет только совпадающую подстроку, P позволит использовать синтаксис регулярных выражений PCRE и | head -1 гарантирует, что вы получите одно совпадение.

Также возможен шаблон POSIX:

 utcdate=$(grep -oE '[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]Z' filename | head -1)
 

где

  • Все (?: они заменяются ( на, так как группы, не связанные с захватом, не поддерживаются POSIX.
  • d заменено на [0-9] (как d не поддерживается регулярным выражением POSIX).

Если вы избежите всего ( , ) , { и } , вы можете удалить E , так как это выражение станет совместимым с POSIX, но это «побег из ада» выглядит уродливо, ИМХО.

Комментарии:

1. На некоторых платформах вы можете использовать -m 1 , чтобы избежать дополнительной трубы head , но я считаю, что это не портативно. macOS grep интерпретирует -m 1 с -o , чтобы ограничить совпадения первой соответствующей строкой, но все равно напечатает несколько совпадений.

2. @tripleee Вот почему я предпочитаю head -1 и использовал его в ответе.

Ответ №2:

С awk помощью вы можете попробовать выполнить следующий код. Это также даст несколько вхождений даты в одной строке.

 awk -v RS='[0-9]{4}-(0[1-9]|1[0-2])-([1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]Z' 'RT{print RT}' Input_file
 

Выше будут напечатаны все вхождения дат во всем Input_file, если вы хотите напечатать только самое первое совпадение, а затем попробуйте выполнить следующее.

 awk -v RS='[0-9]{4}-(0[1-9]|1[0-2])-([1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]Z' 'RT{print RT;exit}' Input_file
 

Объяснение регулярного выражения:

 [0-9]{4}-(0[1-9]|1[0-2])-       ##matching 4 digits followed by - matching 0 1 to 9 OR 1 OR 0 to 2 here.
([1-2][0-9]|3[0-1])T            ##matching 1 to 2 0 to 9 OR 3 0 or 1 here followed by T.
([0-1][0-9]|2[0-3]):[0-5][0-9]  ##match 0 or 1 OR match 2 followed by 0 to 3 colon 0 to 5 followed by 0 to 9.
:[0-5][0-9]Z                    ##matching colon 0 to 5 followed by 0 to 9 followed by Z.