awk : если ›=4 строки подряд начинаются с + или - не печатать запись

Я пытаюсь использовать awk для чтения файла и отображать только строки, которые не начинаются с + или - 4 или более раз подряд. gawk тоже подойдет. Каждая группа отделяется пустой строкой.

Вот образец из файла, это строки, которые я не хочу печатать:

+Host is up.
+Not shown: 95 closed ports, 3 filtered ports
+PORT     STATE SERVICE   VERSION
+23/tcp   open  telnet
+9100/tcp open  jetdirect

-Host is up.
-Not shown: 99 closed ports
-PORT     STATE SERVICE VERSION
-5900/tcp open  vnc

Образец из файла, который я делаю хочу распечатать (не 4 или более подряд):

-Not shown: 76 closed ports, 18 filtered ports
+Not shown: 93 closed ports
PORT    STATE SERVICE VERSION
+514/tcp open  shell

Я изучаю, как использовать awk в данный момент, поскольку я читал awk & sed О'Рейли, но я немного озадачен этой проблемой. Кроме того, если кому-то интересно, я был бы не против увидеть не-awk способы решения этой проблемы с помощью сценария оболочки.

Спасибо!


person jonschipp    schedule 16.07.2012    source источник
comment
Непонятно, что именно вы здесь ищете. Можете ли вы привести более полный пример, например полный (если короткий) входной файл и ожидаемый результат?   -  person danfuzz    schedule 16.07.2012


Ответы (2)


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

Содержание script.awk:

BEGIN {
        ## Separate records by one or more blank lines.
        RS = ""

        ## Each line will be one field. Both for input and output.
        FS = OFS = "\n"
}

## For every paragraph...
{
        ## Flag to check if I will print the paragraph to output.
        ## If 1, print.
        ## If 0, don't print.
        output = 1

        ## Count how many consecutive rows have '+' or '-' as first
        ## character.
        j = 0

        ## Traverse all rows.
        for ( i = 1; i <= NF; i++ ) {
                if ( substr( $i, 1, 1 ) ~ /+|-/ ) {
                        ++j;
                }
                else {
                        j = 0
                }

                if ( j >= 4 ) {
                        output = 0
                        break
                }
        }

        if ( output == 1 ) {
                print $0 "\n"
        }
}

Предполагая, что следующий тестовый входной файл является infile:

+Host is up. 
+Not shown: 95 closed ports, 3 filtered ports
+PORT     STATE SERVICE   VERSION

+Host is up. 
+Not shown: 95 closed ports, 3 filtered ports
+PORT     STATE SERVICE   VERSION
+23/tcp   open  telnet
+9100/tcp open  jetdirect

-Host is up. 
-Not shown: 99 closed ports
-PORT     STATE SERVICE VERSION
-5900/tcp open  vnc 

-Not shown: 76 closed ports, 18 filtered ports
+Not shown: 93 closed ports
PORT    STATE SERVICE VERSION
+514/tcp open  shell

Запустите скрипт следующим образом:

awk -f script.awk infile

Со следующим выводом (первая запись, потому что она не достигает четырех последовательных строк, и вторая запись, потому что между ними есть другая строка):

+Host is up.
+Not shown: 95 closed ports, 3 filtered ports
+PORT     STATE SERVICE   VERSION

-Not shown: 76 closed ports, 18 filtered ports
+Not shown: 93 closed ports
PORT    STATE SERVICE VERSION
+514/tcp open  shell
person Birei    schedule 16.07.2012
comment
Это прекрасно работает. Спасибо! Первоначально я пытался сделать что-то вроде /^[+-]/ ~ $1 с FS по умолчанию, потому что я не знал другого способа сопоставления шаблона. Я думал, что установка RS на пустую строку будет работать, но я не знал, как сопоставить [+-], так как до сих пор я выполнял только сопоставление полей. Спасибо еще раз. - person jonschipp; 16.07.2012
comment
Поскольку вы не предоставляете действия печати (f), как ваш скрипт узнает, когда печатать запись? output - это просто обычная переменная, верно? Я смущен тем, что обеспечивает фактическое действие вывода. - person jonschipp; 17.07.2012
comment
@jonschipp: инструкция print $0 "\n" внутри последнего условия if ( output == 1 ). Флаг output сбрасывается при обнаружении абзаца, состоящего не менее чем из 4 последовательных строк с вашим условием. По умолчанию установлено. $0 имеет весь абзац, а дополнительный \n также предназначен для разделения абзацев в выводе. Это то, о чем вы спрашиваете, или я вас неправильно понял? - person Birei; 17.07.2012
comment
Да это оно. Я просто не заметил печати $0 в разделе кода вашего сообщения (я не прокручивал вниз, чтобы увидеть его). Я переключился на Mac, и полоса прокрутки не отображается, если не зависла в Chrome. Виноват. - person jonschipp; 17.07.2012

person    schedule
comment
Бесполезное использование cat. Кроме того, он не отвечает на вопрос, связанный с количеством строк в блоке, а не с количеством полей в строке. - person chepner; 16.07.2012
comment
В awk вы никогда не должны писать { if( expr ) print $0} в операторе действия. Вместо этого просто напишите expr в качестве оператора шаблона. - person William Pursell; 16.07.2012