команда egrep, чтобы извлечь одну строку, если найти то же слово - PullRequest
0 голосов
/ 02 ноября 2018

Я покажу вам вывод этой команды:

[root@test ~]# df -P -k -t xfs | egrep '*/PATH whichI don't have/*'

Когда я запускаю команду, у меня выводится следующее:

[root@test ~]# df -P -k -t xfs | egrep '*/PATH whichI don't have/*'
10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.40:/var/contain/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/toto  3877121024 215982080 3661138944       6% /fofo
10.20.30.60:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo

Я хочу извлечь только одну строку из разных других строк, если я найду один и тот же путь только один раз. Поэтому я хочу извлечь только одну строку из каждой из нескольких строк. Ожидаемый результат:

[root@test ~]# df -P -k -t xfs | egrep '*/PATH whichI don't have/*'  
10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.60:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo

Если я нахожу один и тот же путь, я хочу извлечь только одну строку из каждых нескольких строк. IP-адрес не совпадает. Если несколько строк содержат один и тот же адрес, я хочу оставить только одну строку. надеюсь, это поможет

Спасибо.

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

Я думаю, что grep - неправильный инструмент для этой работы, и Awk - лучший выбор (также можно использовать Perl или Python, и, без сомнения, другие языки сценариев).

Похоже, вам нужна первая запись для каждого IP-адреса, то есть поле до первого двоеточия в формате журнала. Это говорит о том, что вам нужно:

awk -F: '!($1 in a) { print; a[$1] = 1 }'

Учитывая входное шоу в вопросе, вывод:

10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.60:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo

Не могли бы вы объяснить, что делает команда, пожалуйста?

Awk использует ассоциативные массивы, которые могут принимать строки в качестве индексов. Опция -F: означает, что Awk разбивает строки на поля в двоеточиях, поэтому $1 - это текст перед первым двоеточием (IP-адресом), а (в этом примере) $2 - это весь текст после первого двоеточия. - пока $0 - это целая строка ввода. Программы Awk представляют собой последовательность пар «образец - действие» (или «выражение» или «условие» плюс «действие»). Действие, если оно указано явно, заключено в фигурные скобки (если не указано, по умолчанию используется print $0 - печатать строку ввода). Если шаблон не указан, он эквивалентен сопоставлению всех строк.

В этой программе условие !($1 in a), которое проверяет, отображается ли $1 как индекс в массиве a; общее выражение оценивается как истинное, если индекс не отображается. Когда условие выполняется, действие выполняется. Он печатает (неявно $0) и устанавливает a[$1] в 1, чтобы в случае повторного появления того же IP-адреса условие оценивалось как ложное, предотвращая повторение IP-адреса.

Если бы вы хотели, чтобы последняя запись вместо первой, вы бы использовали вариант схемы, где каждая строка будет сохранена в правильной записи в массиве: { a[$1] = $0 } и тогда у вас будет шаблон END запустить после завершения ввода: END { for (i in a) print a[i] }. Есть бесконечные вариации на тему.


А если я хочу сделать то же самое, но на основе слова после IP-адреса вместо IP-адреса ( / word / ).

Многое зависит от того, как вы определяете слово (или / word / '). Чтобы облегчить свою жизнь, я планирую рассматривать слово как непрерывный набор непустых символов. Разделитель полей может быть регулярным выражением, поэтому я собираюсь использовать [: ] для разделения на двоеточия или пробелы; слово после IP-адреса будет $2. Сценарий почти не меняется:

awk -F '[: ]' '!($2 in a) { print; a[$2] = 1 }'

Поскольку в примерах данных все имена после двоеточия отличаются, все 5 строк появляются в выходных данных. Однако, если вы запускаете сценарий для одного и того же файла несколько раз (добавьте data data после показанного сценария, где файл data содержит входные данные вашего примера), и вы получите только одну копию строк в выводе, что обнадеживает .

0 голосов
/ 02 ноября 2018

Хорошо, при условии, что вы заинтересованы только в части / x / y, я думаю, вы можете сделать это следующим образом:

df -P -k -t xfs > tmpFile
cat tmpFile |cut -d: -f2|cut -d/ -f1-3|sort -u > tmpFile2
while read line; do grep $line tmpFile|head -1; done < tmpFile2

Для данных, которые вы предоставили выше, результат будет

10.20.30.40:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.40:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...