Как извлечь коды с помощью команды grep? - PullRequest
0 голосов
/ 21 апреля 2019

У меня есть файл со строками ввода ниже.

John | 1 | R | Категория не найдена для локальной конфигурации / кода / 123.NNN и клиента 113TOM | 2 | R | Категория не найдена для локальной конфигурации / кода / 123.NNN и клиента 114Категория PETER | 3 | R | не найдена для локальной конфигурации / кода / 456.1 и клиента 115

Мне нужно извлечь только выделенный выше текст с помощью команды grep.

Я попробовал приведенную ниже команду и не получил должного результата.Получение лишних 2 нежелательных символов в выводе.Пожалуйста, предложите, если есть какой-либо другой способ добиться этого с помощью команды grep.

find ./ -type f -name <FileName> -exec cut -f 4 -d'|' {} + |
grep -o 'Category is not found for local configuration/code/...\\....' |
grep -o '...\\....' | sort | uniq

Токовый выход:

123.NNN
456.1 a

Ожидаемый результат:

123.NNN
456.1

Ответы [ 8 ]

2 голосов
/ 21 апреля 2019

Вы можете использовать другое регулярное выражение grep.

find ./ -type f -name f -exec cut -f 4 -d'|' {} +  |
grep -o 'Category is not found for local configuration/code/...\.[^ ]*' |
grep -o '...\..*' | sort | uniq

. соответствует любому символу, [^ ]* соответствует любой последовательности символов до первого пробела

Выход:

123.NNN
456.1
1 голос
/ 21 апреля 2019

Я бы использовал опцию -P:

grep -oP '/code/\K\S+' file | sort -u

Вы хотите извлечь непробельные символы после /code/

1 голос
/ 21 апреля 2019

С sed:

sed -E -n 's#.*code/(.*)\s+and.*#\1#p' file.txt | uniq

Выход:

123.NNN
456.1
1 голос
/ 21 апреля 2019

Ваше регулярное выражение задает фиксированную ширину символа для строк переменной ширины.Исходя из ваших примеров, что-то вроде

[0-9]\+\.[A-Z0-9]\+

может показаться лучшим выражением.Однако, возможно, мы могли бы также упростить это, объединив команды cut и несколько grep в один скрипт Awk.

find etc etc -exec awk -F '|' '
    $4 ~ /Category is not found for local configuration\/code\/[0-9]{3}\.[0-9A-Z]/ {
        split($4, a, /\/code\/);
        split(a[2], b); print b[1] }' {} + |
sort -u

Две операции split - это всего лишь дешевый способ выбратьтекст между /code/ и следующим пробельным символом;с помощью соответствия регулярному выражению мы уже установили, что строка после /code/ соответствует шаблону, который нам нужен.

Обратите также внимание на то, что sort имеет опцию -u, которая позволяет заменить (тривиальнопадежи) uniq.

Вариант регулярного выражения, поддерживаемый Awk, немного отличается от варианта, поддерживаемого POSIX grep;поэтому обратный слэш \+ в диалекте BRE grep является простым + в диалекте, называемом ERE, который [более или менее] поддерживается Awk - и grep -E.Если у вас есть grep -P, вы можете использовать третий вариант, который имеет удобную функцию;

find etc etc -exec grep -oP '^([^|]*[|]){3}[^|]*Category is not found for local configuration/code/\K[0-9]{3}\.[0-9A-Z]+' {} + |
sort -u

\K говорит: «Подойди сюда, но забудь все до этого» и печатает только частьпосле этого токена.

0 голосов
/ 22 апреля 2019

Простые замены в отдельных строках - это то, для чего лучше всего подходит sed. Это будет работать, используя любой sed в любой оболочке на любой машине UNIX:

$ cat file
John|1|R|Category is not found for local configuration/code/123.NNN and customer 113
TOM|2|R|Category is not found for local configuration/code/123.NNN and customer 114
PETER|3|R|Category is not found for local configuration/code/456.1 and customer 115

$ sed -n 's:.*Category is not found for local configuration/code/\([^ ]*\).*:\1:p' file | sort -u
123.NNN
456.1
0 голосов
/ 21 апреля 2019

Single sed может выполнять фильтрацию. (Шаблон может быть дополнительно обобщен, как предложено другими, если это вариант. Но будьте осторожны, чтобы не слишком упрощать, чтобы он мог совпадать с неожиданными входными данными)

sed -nE 's@(\S+\s+){6}configuration/code/(\S+)\s.*@\2@p' input.txt

Чтобы заменить вашу точную команду,

find ./ -type f -name <Filename> -exec cat {} \; | sed -nE 's@(\S+\s+){6}configuration/code/(\S+)\s.*@\2@p' | sort | uniq
0 голосов
/ 21 апреля 2019

awk с использованием match():

$ awk 'match($0,/[0-9]+\.[A-Z0-9]+/)&&++a[(b=substr($0,RSTART,RLENGTH))]==1{print b}' file

Выход:

123.NNN
456.1

Довольно напечатано для немного лучшей читаемости:

$ awk '
match($0,/[0-9]+\.[A-Z0-9]+/) && ++a[(b=substr($0,RSTART,RLENGTH))]==1 {
    print b
}' file
0 голосов
/ 21 апреля 2019

Это невозможно, просто используя grep.Вместо этого следует использовать AWK:

awk '{split($7, ar, "/"); print ar[3]}' FILE

Объяснение:

  • Функция split разбивает строку, здесь $7, седьмое поле, помещаярезультат в массиве ar с использованием строки / в качестве разделителя.
  • Затем печатается 3-е поле массива.

Примечание:

  • Я предполагаю, что все вашего ввода выглядят как образцы, которые вы нам дали, то есть:
aaa|b|c|ddd is not found for local configuration/code/111.nnn and customer nnn

Где aaa и ddd будутне содержит пробелов.

  • Я также предполагаю, что у вас действительно есть файл FILE, содержащий эти строки.Это немного неясно.

Ввод:

▶ cat FILE
John|1|R|Category is not found for local configuration/code/123.NNN and customer 113
TOM|2|R|Category is not found for local configuration/code/123.NNN and customer 114
PETER|3|R|Category is not found for local configuration/code/456.1 and customer 115

Ввод:

▶ awk '{split($7, ar, "/"); print ar[3]}' FILE 
123.NNN
123.NNN
456.1
...