Как выполнить многострочный grep

Как вы выполняете grep для текста, который появляется на двух строках?

Например:

  • unix: получить символы от 10 до 80 в файле
  • Выполнение awk для каждого файла, найденного с помощью find, а затем перенаправление результата на новое имя файла
  • неожиданный вывод с помощью grep
  • полностью игнорировать строки, начинающиеся с определенного шаблона
  • Как я могу разделить строку на две строки, если длина больше 7 с помощью awk?
  • Как grep для нескольких шаблонов на нескольких строках?
  • pbsnodes – это команда, которую я использую, которая возвращает использование кластера linux

     root$ pbsnodes node1 state = free procs = 2 bar = foobar node2 state = free procs = 4 bar = foobar node3 state = busy procs = 8 bar = foobar 

    Я хочу определить количество проков, которые соответствуют узлам, находящимся в состоянии «бесплатно». До сих пор мне удалось определить «количество проков» и «узлы в свободном состоянии», но я хочу объединить их в одну команду, которая показывает все свободные procs.

    В приведенном выше примере правильным ответом будет 6 (2 + 4).

    Что у меня есть

     root$ NUMBEROFNODES=`pbsnodes|grep 'state = free'|wc -l` root$ echo $NUMBEROFNODES 2 root$ NUMBEROFPROCS=`pbsnodes |grep "procs = "|awk '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'` root$ echo $NUMBEROFPROCS 14 

    Как я могу искать каждую строку, которая читает «procs = x», но только если строка над ней читает «state = free»?

  • добавить в файл добавочный столбец идентификатора
  • awk не может печатать элемент массива
  • Заменить кратчайшее совпадение строкового рисунка
  • Как извлечь текст с помощью sed
  • Изменение вхождения строки в файл при соблюдении новых строк строки DOS
  • объединение двух файлов в соответствии с общим столбцом
  • 8 Solutions collect form web for “Как выполнить многострочный grep”

    Если данные всегда в этом формате, вы можете просто написать его:

     awk -vRS= '$4 == "free" {n+=$7}; END {print n}' 

    ( RS= означает, что записи являются абзацами ).

    Или:

     awk -vRS= '/state *= *free/ && match($0, "procs *=") { n += substr($0,RSTART+RLENGTH)}; END {print n}' 
     $ pbsnodes node1 state = free procs = 2 bar = foobar node2 state = free procs = 4 bar = foobar node3 state = busy procs = 8 bar = foobar $ pbsnodes | grep -A 1 free state = free procs = 2 -- state = free procs = 4 $ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' 2 4 $ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ 2+4 $ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ | bc 6 

    https://en.wikipedia.org/wiki/Pipeline_(Unix)

    Вот один из способов сделать это с помощью pcregrep .

     $ pbsnodes | pcregrep -Mo 'state = free\n\s*procs = \K\d+' 2 4 

    пример

     $ pbsnodes | \ pcregrep -Mo 'state = free\n\s*procs = \K\d+' | \ awk '{ sum+=$1 }; END { print sum }' 6 

    Ваш выходной формат загрунтован для абзаца абзаца Perl:

     pbsnodes|perl -n00le 'BEGIN{ $sum = 0 } m{ state \s* = \s* free \s* \n procs \s* = \s* ([0-9]+) }x and $sum += $1; END{ print $sum }' 

    Заметка

    Это работает только потому, что идея Perl о «абзаце» представляет собой кусок непустых строк, разделенных одной или несколькими пустыми строками. Если у вас не было пустых строк между разделами node , это не сработало бы.

    Смотрите также

    • Чтение абзаца за раз
    • PerlRun

    Если у вас есть данные фиксированной длины (фиксированная длина относится к числу строк в записи), в sed вы можете использовать команду N (несколько раз), которая соединяет следующую строку с пространством шаблона:

     sed -n '/^node/{N;N;N;s/\n */;/g;p;}' 

    должен дать вам выход:

     node1;state = free;procs = 2;bar = foobar node2;state = free;procs = 4;bar = foobar node3;state = busy;procs = 8;bar = foobar 

    Для переменной записи (например, с пустой разделительной линией) вы можете использовать команды ветвления t и b , но awk , скорее всего, доставит вас туда более удобным способом.

    GNU-реализация grep поставляется с двумя аргументами, чтобы также печатать строки перед ( -B ) и после ( -A ) совпадением. Фрагмент страницы:

      -A NUM, --after-context=NUM Print NUM lines of trailing context after matching lines. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or --only-matching option, this has no effect and a warning is given. -B NUM, --before-context=NUM Print NUM lines of leading context before matching lines. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or --only-matching option, this has no effect and a warning is given. 

    Поэтому в вашем случае вам нужно будет grep для state = free а также распечатать следующую строку. Объединив это с фрагментами из вашего вопроса, вы придете к чему-то вроде этого:

     usr@srv % pbsnodes | grep -A 1 'state = free' | grep "procs = " | awk '{ print $3 }' | awk '{ sum+=$1 } END { print sum }' 6 

    и немного короче:

     usr@srv % pbsnodes | grep -A 1 'state = free' | awk '{ sum+=$3 } END { print sum }' 6 

    … и вот решение Perl:

     pbsnodes | perl -lne 'if (/^\S+/) { $node = $& } elsif ( /state = free/ ) { print $node }' 

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

     $ pbsnodes | awk 'BEGIN { freeprocs = 0 } \ $1=="state" && $3=="free" { getline; freeprocs+=$3 } \ END { print freeprocs }' 

    От man awk :

      getline Set $0 from next input record; set NF, NR, FNR. getline <file Set $0 from next record of file; set NF. getline var Set var from next input record; set NR, FNR. getline var <file Set var from next record of file. command | getline [var] Run command piping the output either into $0 or var, as above. command |& getline [var] Run command as a co-process piping the output either into $0 or var, as above. Co-processes are a gawk extension. 
    Linux и Unix - лучшая ОС в мире.