Как разделить текстовый файл на записи первым несимволом пробела с помощью awk и распечатать только записи, содержащие строку

[1127947]In Perl:

1
21.05.2016, 03:00
4 ответа

Ваша идея использовать регекс-разделитель записей элегантна, но помните, что awk будет потреблять соответствующий текст, который в вашем случае будет первым не белым пробелом символа после записи.

Если ваша система имеет GNU версию awk, вы можете получить доступ к самой последней согласованной RS через переменную RT, однако вам все равно нужно будет сохранить результат, чтобы зашивать его обратно в начало следующей записи - возможно, что-то вроде

gawk 'BEGIN{RS="\n[^[:blank:]]"}; {lastRT=RT}; /apollo/ {$0=substr(lastRT,2)""$0; print}' file.txt

Подложка (lastRT,2) просто удаляет новую строку из совпадения, так что префиксом будет только символ без пробелов.

2
27.01.2020, 23:13

с awk и параметром

(файл filter.awk)

BEGIN { p=0 ; } # no printing
 { if ( (substr($0,1,1) != " ") && (substr($0,1,1) != "\t" ) ) p=0 ; # if no blank stop printing
   if ( index($0,name) > 1 ) p=1 ; # pattern found ?
  if (p) print ;
 }
  • $ 0 - это вся строка
  • substr ($ 0,1,1) - первый символ строки

и результат

awk -v name=apollo -f filter.awk a.txt

    com.apollo.apollonetworkcheck
     1026ms running, 88 wakeups
     88 alarms: flg=0x14
1
27.01.2020, 23:13

Я также бросаю perl на все, но иногда добавляю sed для аромата:

$ sed  's/^\w/\n&/' file | perl -000ne 'print if /apollo/'
com.apollo.apollonetworkcheck
    1026ms running, 88 wakeups
    88 alarms: flg=0x14

sed добавит дополнительную новую строку между каждой пластинкой. Он просто ищет строки, которые начинаются с буквенно-цифрового символа (^\w) и заменяет этот символ на новую строку, а затем на сам символ (\n&, & означает "независимо от того, что вы только что сопоставили"). В результате получается файл, в котором записи выглядят как параграфы, перед ними пустая строка.

Теперь мы можем использовать "параграфный режим" на perl, активированный в -000. В сочетании с -n (считывание входной записи за записью) это позволяет нам прочитать всю запись сразу. Таким образом, достаточно вывести на печать текущую "линию" (запись), если она соответствует желаемому шаблону. В данном случае apollo.

Я не уверен, насколько портативна нотация \w. Если ваш sed не может с этим справиться, используйте вместо этого:

sed  's/^[^ \t]/\n&/' file | perl -000ne 'print if /apollo/'

Вы также можете использовать тот же подход с awk:

$ sed  's/^[^ \t]/\n&/' file | awk -v RS="\n\n" '/apollo/'
com.apollo.apollonetworkcheck
     1026ms running, 88 wakeups
     88 alarms: flg=0x14
1
27.01.2020, 23:13

Я всегда бросаю perl на все :-)

perl -ne 'if (/^\s/) { $x.=$_ }else{print $x if $x=~/apollo/; $x=$_} END {print $x if $x=~/apollo/}' file.txt

Правка: объяснение однострочности:

  • -n подразумевает цикл над вводом, а не печать по умолчанию в конце каждого цикла (-p то же самое, но по умолчанию выводит строку).
  • -e определяет выражение или фрагмент кода. Это выполняется внутри неявного цикла.
  • Я использую переменную $ x для буферизации входящего текста до тех пор, пока не будет найдена полная «запись».
  • / ^ \ s / соответствует пробелу в начале строки. Если он найден, строка ввода добавляется в буфер $ x. Если нет, то «запись» завершается и проверяется на наличие поисковой строки «apollo». Если он найден, запись печатается. После обработки буфер очищается.
  • Часть END {} выполняется после завершения цикла для обработки регистра последней записи во входных данных.
3
27.01.2020, 23:13

Теги

Похожие вопросы