Использование нескольких разделителей в awk


202

У меня есть файл, который содержит следующие строки:

/logs/tc0001/tomcat/tomcat7.1/conf/catalina.properties:app.env.server.name = demo.example.com
/logs/tc0001/tomcat/tomcat7.2/conf/catalina.properties:app.env.server.name = quest.example.com
/logs/tc0001/tomcat/tomcat7.5/conf/catalina.properties:app.env.server.name = www.example.com

В приведенном выше выводе я хочу извлечь 3 поля (число 2, 4 и последнее *.example.com). Я получаю следующий вывод:

cat file | awk -F'/' '{print $3 "\t" $5}'
tc0001   tomcat7.1
tc0001   tomcat7.2
tc0001   tomcat7.5

Как мне также извлечь последнее поле с именем домена после '='? Как использовать multiple delimiterдля извлечения поля?


2
Чтобы ответить на мой вопрос, который одинаков, но различен, awkон глотал поля, когда они были пустыми, что указывало на нумерацию полей. Я перешел -F " "на -F "[ ]"и awkбольше не глотал пустые поля.
Адам

Ответы:


324

Разделитель может быть регулярным выражением.

awk -F'[/=]' '{print $3 "\t" $5 "\t" $8}' file

Производит:

tc0001   tomcat7.1    demo.example.com  
tc0001   tomcat7.2    quest.example.com  
tc0001   tomcat7.5    www.example.com

42
Конечно, catпроцесс не требуется awk '...' file. Кроме того, было бы лучше использовать разделитель выходного поля:awk -F'[/=]' -v OFS="\t" '{print $3, $5, $8}'
Гленн Джекман

17
Ограничители Awk могут быть регулярными выражениями ... это сделало мой день!
das.cyklone

4
@ das.cyklone: ​​awk также может иметь несколько разделителей, с |: ex: awk -F 'this|that|[=/]' '......' (полезно, чтобы слова / строки разделяли вещи) (обратите внимание, что это сохраняет пробелы в полях между двумя разделителями. Добавление также |[ \t]+может быть полезно, но может сделать вещи хитрый ... так как часто есть пробелы до и после 'this', это заставит 2 дополнительных пустых поля появиться между пробелом (ами) и 'this')
Оливье Дюлак

Я пробовал это на 2 разных дистрибутивах, и у меня такое же поведение: я хочу получить порт из netstat -ntpl "netstat -ntpl | sed 's /: / /' | awk '{print $ 5}'", но работает может обойтись без doulbe piping Это работает, но я не ожидал данных в поле 17: "netstat -ntpl | awk -F" |: "'{print $ 17}'"
louigi600

2
да ... это дало мне то, что я хотел: awk -F "[:] +" '/ \ / postmaster * $ / {print $ 5}'
louigi600

44

Хорошие новости! awkРазделитель полей может быть регулярным выражением. Вам просто нужно использовать -F"<separator1>|<separator2>|...":

awk -F"/|=" -vOFS='\t' '{print $3, $5, $NF}' file

Возвращает:

tc0001  tomcat7.1  demo.example.com
tc0001  tomcat7.2  quest.example.com
tc0001  tomcat7.5  www.example.com

Вот:

  • -F"/|="устанавливает разделитель поля ввода в либо /или =. Затем он устанавливает разделитель выходного поля на вкладку.

  • -vOFS='\t'использует -vфлаг для установки переменной. OFSпеременная по умолчанию для разделителя полей вывода, и она установлена ​​на символ табуляции. Флаг необходим, потому что нет встроенного для OFS, как -F.

  • {print $3, $5, $NF} печатает 3-е, 5-е и последнее поля на основе разделителя поля ввода.


Смотрите другой пример:

$ cat file
hello#how_are_you
i#am_very#well_thank#you

Этот файл имеет два разделителя полей #и _. Если мы хотим напечатать второе поле независимо от того, является ли разделитель одним или другим, давайте сделаем оба разделителями!

$ awk -F"#|_" '{print $2}' file
how
am

Где файлы нумеруются следующим образом:

hello#how_are_you           i#am_very#well_thank#you
^^^^^ ^^^ ^^^ ^^^           ^ ^^ ^^^^ ^^^^ ^^^^^ ^^^
  1    2   3   4            1  2   3    4    5    6

1
Спасибо @BUFU за ваше редактирование. Я удалил ссылку OFS, чтобы просто сосредоточиться на части FS, но это также хорошо иметь ее. Ура!
Федорки "ТАК прекрати вредить"

5

Если ваш пробел соответствует, вы можете использовать его в качестве разделителя, также вместо \tпрямой вставки вы можете установить разделитель вывода, и он будет включен автоматически:

< file awk -v OFS='\t' -v FS='[/ ]' '{print $3, $5, $NF}'

3

Для разделителя полей любого числа 2через 5или букву aили #или пробел, где разделительный символ должен повторяться не менее 2 раз и не более 6 раз, например:

awk -F'[2-5a# ]{2,6}' ...

Я уверен, что вариации этого существуют с использованием () и параметров


3

Perl однострочный:

perl -F'/[\/=]/' -lane 'print "$F[2]\t$F[4]\t$F[7]"' file

Эти параметры командной строки используются:

  • -nзацикливать каждую строку входного файла, помещать строку в $_переменную, автоматически не печатать каждую строку

  • -l удаляет символы новой строки перед обработкой и добавляет их обратно после

  • -aРежим автоматического разделения - Perl автоматически разбивает входные строки в @Fмассив. По умолчанию расщепление по пробелам

  • -FМодификатор AutoSplit, в этом примере , расщепляется на любой /или=

  • -e выполнить код Perl

Perl тесно связан с awk, однако @Fмассив autosplit начинается с индекса, $F[0]а поля awk начинаются с $ 1.


2

Другой вариант - использовать опцию -F, но передать ее через регулярное выражение, чтобы напечатать текст между левой и / или правой круглой скобкой ().

Содержание файла:

528(smbw)
529(smbt)
530(smbn)
10115(smbs)

Команда:

awk -F"[()]" '{print $2}' filename

результат:

smbw
smbt
smbn
smbs

Использование awk, чтобы просто напечатать текст между [] :

Используйте, awk -F'[][]' но awk -F'[[]]'не будет работать.

http://stanlo45.blogspot.com/2020/06/awk-multiple-field-separators.html


Ваш ответ появился в очереди на удаление, потому что в 9 случаях из 10 пользователи с 1 репутацией, ссылающиеся на собственный блог, обычно являются спамом. Но твое исключение из правил. Последние 10 лет контента там есть золотой рудник, надеюсь, у вас есть план его увековечить.
Эрик Лещинский

0

Я вижу много идеальных ответов на доске, но все же хотел бы загрузить свой кусок кода тоже,

awk -F"/" '{print $3 " " $5 " " $7}' sam | sed 's/ cat.* =//g'


2
print $3 " " $5 " " $7может быть напечатан так же, как print $3, $5, $7. Кроме того, я не вижу преимущества использования awk и последующего использования sed. В общем, awk может быть достаточно, и другие ответы показывают это.
Федорки 'ТАК прекрати вредить'
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.