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

Имам файл, който съм разделил на куп различни заглавия. Трябва да изведа определени полета под определено заглавие. Например искам да отпечатам имена под заглавието ПРИОРИТЕТНИ ПОТРЕБИТЕЛИ. Мога да направя grep за този сегмент с помощта на grep и да отпечатам имената (като grep -A 10 "ПРИОРИТЕТНИ ПОТРЕБИТЕЛИ"| grep име:), но трябва да огранича изхода си само до имена под заглавието ПРИОРИТЕТНИ ПОТРЕБИТЕЛИ. Проблемът е, че броят на записите под всяко заглавие варира, така че не мога да използвам фиксирано число с опцията 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

котка sample.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 | grep име

   name: Jack
   name: Joe

'/ПРИОРИТЕТНИ ПОТРЕБИТЕЛИ/,/СЕГМЕНТ3/' ПРИОРИТЕТНИТЕ ПОТРЕБИТЕЛИ са началният модел, а СЕГМЕНТ3 е крайният шаблон, ние отпечатваме само редовете между тези 2 шаблона и след това получаваме 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
Здравей thx - няма празен ред над всеки сегмент - понякога има понякога няма ,, не съм сигурен дали командата sed ще работи правилно .. командата awk изобщо не мога да започна работа - person theuniverseisflat; 26.01.2016
comment
@theuniverseisflat - Не си разбрал правилно. Във вашия пример заглавията се появяват на редове, в които или няма интервал в колона 1, или точно един интервал в колона 1. Тествах програмата awk, използвайки три различни awks (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