#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
, но я считаю, что это не портативно. macOSgrep
интерпретирует-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.