Попытка написать регулярное выражение для захвата заданных буквенно-цифровых значений, но также для захвата других числовых значений. Каким должен быть правильный способ получить результат желания?
код
grep -Eo '(\[[[:alnum:]]\)\w+' file > output
$ cat file
2022-04-29 08:45:11,754 [14] [Y23467] [546] This is a single line
2022-04-29 08:45:11,764 [15] [fpes] [547] This is a single line
2022-04-29 08:46:12,454 [143] [mwalkc] [548] This is a single line
2022-04-29 08:49:12,554 [143] [skhat2] [549] This is a single line
2022-04-29 09:40:13,852 [5] [narl12] [550] This is a single line
2022-04-29 09:45:14,754 [1426] [Y23467] [550] This is a single line
выходной ток -
[14
[Y23467
[546
[15
[fpes
[547
[143
[mwalkc
[548
[143
[skhat2
[549
[5
[narl12
[550
[1426
[Y23467
[550
ожидаемый результат -
Y23467
fpes
mwalkc
skhat2
narl12
Y23467
1-е решение: С показанными образцами попробуйте выполнить код awk
. Простым объяснением будет использование функции gsub
для замены [
и ]
в 4-м поле, после чего печатается 4-е поле.
awk '{gsub(/\[|\]/,"",$4);print $4}' Input_file
2-е решение: С GNU grep
попробуйте следующее решение.
grep -oP '^[0-9]{4}(-[0-9]{2}){2} [0-9]{2}(:[0-9]{2}){2},[0-9]{1,3} \[[0-9]+\] \[\K[^]]*' Input_file
Объяснение: Добавлено подробное объяснение приведенного выше регулярного выражения, используемого в GNU grep
.
^[0-9]{4}(-[0-9]{2}){2} ##From starting of value matching 4 digits followed by dash 2 digits combination of 2 times.
[0-9]{2}(:[0-9]{2}){2} ##Matching space followed by 2 digits followed by : 2 digits combination of 2 times.
,[0-9]{1,3} ##Matching comma followed by digits from 1 to 3 number.
\[[0-9]+\] \[\K ##Matching space followed by [ digits(1 or more occurrences of digits) followed by space [ and
##then using \K to forget all the previously matched values.
[^]]* ##Matching everything just before 1st occurrence of ] to get actual values.
Решение GNU grep было тем, что я надеялся сделать. Спасибо за предложение.
Использование sed
$ sed 's/\([^[]*\[\)\{2\}\([^]]*\).*/\2/' input_file
Y23467
fpes
mwalkc
skhat2
narl12
Y23467
Использование [[:alnum:]]
или \w
означает, что он может соответствовать буквенно-цифровым или словесным символам.
Если могут быть числа, но должен быть символ az и поддерживается использование -P
для perl-совместимого регулярного выражения:
grep -oP '\[\K\d*[A-Za-z][\dA-Za-z]*(?=])' file
Объяснение
\[
Матч [
\K
Забудьте, что совпало до сих пор\d*[A-Za-z]
Сопоставьте необязательные цифры и хотя бы один символ a-zA-Z[\dA-Za-z]*
Сопоставьте необязательные символы a-zA-Z и цифры(?=])
Утвердить ]
вправоВыход
Y23467
fpes
mwalkc
skhat2
narl12
Y23467
Если может быть только 1 вхождение, вы также можете использовать sed с группой захвата \(...\)
и использовать группу в замене, используя \1
sed 's/.*\[\([[:digit:]]*[[:alpha:]][[:alnum:]]*\)].*/\1/' file
Ваша проблема состоит из нескольких частей. Сначала я попытаюсь помочь вам с вашим регулярным выражением (но это, вероятно, откроет больше проблем); далее я покажу вам альтернативу.
Что нужно понимать о [[:alnum:]]
, так это то, что он захватывает все, что содержит буквенно-цифровой символ. Таким образом, он захватит «123» и «abc», поскольку все эти символы являются буквенно-цифровыми. Он оценивает каждый символ индивидуально и не может захватывать «только разделы, в которых есть как цифры, так и буквы», как вы хотите.
Однако, объединив несколько grep
вместе, мы могли бы отфильтровать строки, содержащие только числа.
grep -Eo '(\[[[:alnum:]]\)\w+' file | grep -v -Eo '\[[[:digit:]]+(\w+|$)' > output
Чтобы уточнить это, в вашем регулярном выражении есть пара ошибок. Во-первых, вы включили \[
внутрь захваченной части, поэтому он захватывает [
в ваших результатах, поэтому вам следует изменить (\[
на \[(
, чтобы переместить [
за пределы захваченной части в скобках ( ... )
.
Далее, ваша комбинация [[:alnum:]]
с \w+
, вероятно, не дает того, что вы ожидаете. Он ищет один буквенно-цифровой символ, за которым следует один или несколько «словных» символов (это все буквенно-цифровые символы плюс некоторые дополнительные). Вы, вероятно, хотите ([[:alnum:]]+)
вместо ([[:alnum:]])\w+
Почему бы не использовать cut
вместо этого? cut -d' ' -f4
займет 4-е поле (с пробелом в качестве разделителя между полями)
$ cut -d' ' -f 4 file
[Y23467]
[fpes]
[mwalkc]
[skhat2]
[narl12]
[Y23467]
Если вы также хотите удалить квадратные скобки, попробуйте
$ cut -d' ' -f 4 file | grep -Eo '\w+'
Y23467
fpes
mwalkc
skhat2
narl12
Y23467
Использование FPAT
с GNU awk
:
awk -v FPAT='[[[:alnum:]]*]' '{gsub(/^\[|\]$/, "",$(NF-1));print $(NF-1)}' file
Y23467
fpes
mwalkc
skhat2
narl12
Y23467
установив FPAT
как '[[[:alnum:]]*]'
, мы сопоставляем [
char, за которым следует ноль или другие буквенно-цифровые символы, за которыми следует ]
char.
с помощью функции gsub()
мы удаляем начальные [
и конечные ]
символы.
мы печатаем поле, предшествующее последнему полю, то есть поле $(NF-1)
, без символов [
и ]
.
Текущий вывод — это не это, а ошибка
grep: Unmatched ( or \(
(поскольку первая открывающая скобка — это группа, а закрывающая скобка экранирована, то это символ)
(вместо закрытия группы).