Разбор раздела файла с определенным заголовком с помощью awk, sed, grep

У меня есть файл, который разбит на кучу разных заголовков. Мне нужно найти определенные поля под определенным заголовком. Например, я хочу напечатать имена под заголовком ПРИОРИТЕТНЫЕ ПОЛЬЗОВАТЕЛИ. Я могу найти этот сегмент с помощью grep и вывести имена (например, grep -A 10 "PRIORITY USERS" | имя grep: ), но мне нужно ограничить свой вывод только именами в заголовке PRIORITY USERS. Проблема в том, что количество записей под каждым заголовком варьируется, поэтому я не могу использовать фиксированное число с опцией grep -A.

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

Входной файл

USERS:

           name: 286
           fields1
           fields 3 

           name: 123
           fieldx: test


PRIORITY USERS:

           name: jack
           field1:  8
           name: Joe


           name: bob
           field1: xyz

           name: tempo
           kind: Text


 SEGMENT3 

           name: ginger
           name: max

 Non-USERS

           Name: JOJO 

Вывод должен быть:

PRIORITY USERS:  

    name: jack 
    name: bob
    name: tempo 

Заранее всем спасибо


person theuniverseisflat    schedule 25.01.2016    source источник
comment
У вас ДЕЙСТВИТЕЛЬНО есть некоторые строки заголовка, которые начинаются в начале строки и имеют суффикс : (например, ПРИОРИТЕТНЫЕ ПОЛЬЗОВАТЕЛИ:), в то время как другие могут иметь пробелы до/после них и не : после них (например, (СЕГМЕНТ3)? Если да, то как Можем ли мы отличить заголовок от любой другой строки в файле? Если нет, отредактируйте свой вопрос, чтобы сделать образец ввода точным, чтобы мы могли попытаться помочь вам решить вашу реальную проблему, а не какую-то проблему, которой у вас на самом деле нет. Также почему name: joe не входит в ожидаемый результат?   -  person Ed Morton    schedule 26.01.2016


Ответы (4)


$ cat tst.awk
/^[[:space:]]?[^[:space:]]/ { inSect = ($0 ~ ("^[[:space:]]?" sect "[[:space:]:]*$") ? 1 : 0) }
inSect && ($0 ~ "^[[:space:]]+" field ":")

$ awk -v sect='PRIORITY USERS' -v field='name' -f tst.awk file
           name: jack
           name: Joe
           name: bob
           name: tempo

Вышеупомянутое сложно из-за того, что ваш формат ввода настолько сильно различается: некоторые строки заголовка начинаются с пробела, другие - нет, некоторые имеют немедленную точку с запятой в конце, а другие - пробелы и т. д., и предполагается, что вы только что пропустили name: joe из ожидаемого вывода. .

person Ed Morton    schedule 26.01.2016

образец кошки.csv

USERS:

           name: 286
           fields1
           fields 3

           name: 286
           fields 4

PRIORITY USERS:

           name: Jack
           field1:  8
           name: Joe

 SEGMENT3

           name: ginger
           name: max

 Non-USERS

           Name: JOJO

sed -n '/ПРИОРИТЕТНЫЕ ПОЛЬЗОВАТЕЛИ/,/СЕГМЕНТ3/p' sample.csv | имя группы

   name: Jack
   name: Joe

'/PRIORITY USERS/,/SEGMENT3/' PRIORITY USERS — это начальный шаблон, а SEGMENT3 — конечный шаблон, мы печатаем только строки между этими двумя шаблонами, а затем получаем name

person Haifeng Zhang    schedule 25.01.2016
comment
Привет, спасибо за обратную связь. Это сработало для одного сегмента файла, но когда я попробовал другой, он указал имя в дополнительных сегментах.. не знаю, почему это работает для одного сегмента, а не для другого. - person theuniverseisflat; 26.01.2016
comment
попробуйте удалить 3 из конечного шаблона SEGMENT3 - person Haifeng Zhang; 26.01.2016

Похоже, что заголовки верхнего уровня можно охарактеризовать как встречающиеся в строках, начинающихся не более чем с одного пробела. Если это так, то следующее имеет то преимущество, что не требует знания заголовка верхнего уровня после целевого заголовка:

sed -r -n '/^ ?PRIORITY USERS/,/^ ?[^ ]/ {/name:/p ; }'

(Некоторые версии sed требуют -E вместо -r для расширенной поддержки регулярных выражений.)

В любом случае нет необходимости вызывать одновременно sed и grep.

Одним из преимуществ использования «awk» здесь является то, что вы можете использовать «?» в регулярных выражениях без установки флага:

awk '/^ ?PRIORITY USERS/ {s++; next}
     s==1 {if (/^ ?[^ ]/) {s++} else if (/name:/) {print}}'
person peak    schedule 25.01.2016
comment
Привет, спасибо - над каждым сегментом нет пустой строки - иногда есть, иногда нет, я не уверен, что команда sed будет работать правильно .. команда awk, которую я вообще не могу заставить работать - person theuniverseisflat; 26.01.2016
comment
@theuniverseisflat - Вы неправильно поняли. В вашем примере заголовки появляются в строках, в которых либо нет пробела в столбце 1, либо ровно один пробел в столбце 1. Я протестировал программу awk, используя три разных awk (Mac OS awk 20070501, gawk и mawk). - person peak; 26.01.2016

awk на помощь!

$ awk -v RS= 'f{print;exit} /PRIORITY USERS:/{f=1}' file

           name: ack
           field1:  8
           name: Joe

Наверное, также есть негласное требование отфильтровывать строки без имен. Для этого немного изменим скрипт

$ awk -F'\n' -v RS= 'f{for(i=1;i<=NF;i++) if($i~/name:/) print $i;exit}
     /PRIORITY USERS:/{f=1}' file

           name: ack
           name: Joe

ОБНОВЛЕНИЕ: на основе обновленного входного файла будет создан список имен

$ awk '/SEGMENT3/{f=0} f&&/name:/; /PRIORITY USERS:/{f=1}' file

           name: jack
           name: Joe
           name: bob
           name: tempo

Примечание. В выходном образце отсутствует "Джо". Если вместо этого вы пропустили «боб», это была хорошая шутка!

person karakfa    schedule 25.01.2016
comment
Привет, спасибо еще раз за помощь. Я изменил входной файл. Наше решение печатает только первый набор данных в разделе ПРИОРИТЕТНЫЕ ПОЛЬЗОВАТЕЛИ (извините, я не указал, что в каждом сегменте есть дополнительные данные. См. измененный текст ввода выше - person theuniverseisflat; 26.01.2016
comment
Что указывает на конец блока? Тег SEGMENT3? - person karakfa; 26.01.2016
comment
Привет, извините за задержку с ответом .. каждый раздел четко идентифицируется по имени. есть как минимум 10 разделов, и они появляются по порядку ПРОЦЕСС: ПОЛЬЗОВАТЕЛИ: МОНТАЖНЫЕ УСЛУГИ и т. д. И Т. Д. Еще раз спасибо за помощь - person theuniverseisflat; 26.01.2016