Есть ли альтернатива grep -A -B -C-переключателям (для печати нескольких строк до и после)?

grep -A 2 -B 3 

печатает 2 строки после строки grep и печатает 3 строки раньше.

 grep -C 3 

печатает 3 строки до и 3 строки после

К сожалению, grep который я использую, не поддерживает эти параметры. Существуют ли альтернативные команды или сценарий для имитации этого? С помощью сценариев sed / awk / perl / shell?

6 Solutions collect form web for “Есть ли альтернатива grep -A -B -C-переключателям (для печати нескольких строк до и после)?”

Один умеренно уродливый способ сделать это

 grep -v pattern file >file.tmp; diff -c file.tmp file 

или замените -c на -C NUM для NUM строк контекста. Тем не менее, это даст дополнительный результат. (Если ваш diff поддерживает -u / -U NUM , он будет чище.)

Если ваш diff не имеет -c / -C / -u , все еще есть способы сделать это, но они довольно уродливые. С другой стороны, система, diff которой даже не поддерживает -c вероятно, также не имеет Perl.

ack требует только Perl и включает опции -A , -B и -C , которые работают как grep. Он использует синтаксис regex Perl вместо grep, и способ, которым он выбирает файлы для поиска, совсем другой. Возможно, вы захотите попробовать параметр -f при его использовании (который распечатывает файлы, которые он будет искать, и фактически ничего не ищет).

Он может быть установлен как один сценарий , для которого не требуются неосновные модули. Просто запустите его в свой каталог ~/bin (или где-либо еще на вашем PATH, на который у вас есть доступ на запись), и убедитесь, что он является исполняемым файлом chmod .

Этот простой скрипт perl эмулирует grep -A в некоторой степени

 #!/usr/bin/perl $pattern=shift; #patthern to search $lines=shift; # number of lines to print $n = 0; while (<>) { $n = $lines if /$pattern/; # reset counting if ($n) { print; $n-- } # print if within $n = 0 if eof; # don't leak across file boundaries } 

Обратите внимание, что вы можете добавить инструкцию использования, чтобы сделать скрипт читаемым и пригодным для использования;)

 USAGE: $./grep-A.pl <pattern> <numLines> <filename> 

Вы можете просто установить GNU grep или Ack (написанный на Perl, понимающий многие опции GNU grep и многое другое).

Если вы предпочитаете использовать стандартные инструменты и немного скриптов, вот скрипт awk, который эмулирует поведение опций -A и -B GNU grep. Минимально проверены.

 #!/bin/sh # grep-ac: a grep-like awk script # Arguments: pattern = awk regexp to search for # before = number of lines to print before a match # after = number of lines to print after a match { "exec" "awk" "-f" "$0" "$@"; } # The array h contains the history of lines that haven't been printed # but are eligible for being "before" lines. # The variable until contains the number of the last "after" line to print. match($0, pattern) { # the current line matches for (i in h) { print h[i]; # print each remaining before line delete h[i]; # delete each line as it's printed } until=NR+after; # record the last after line to print } { if (NR<=until) print $0; # from a match to its last after line: print else h[NR]=$0; # after that: save in history delete h[NR-before]; # remove line too old to be a before line } END {exit !until} # exit status: 0 if there was a match, else 1 того, как #!/bin/sh # grep-ac: a grep-like awk script # Arguments: pattern = awk regexp to search for # before = number of lines to print before a match # after = number of lines to print after a match { "exec" "awk" "-f" "$0" "$@"; } # The array h contains the history of lines that haven't been printed # but are eligible for being "before" lines. # The variable until contains the number of the last "after" line to print. match($0, pattern) { # the current line matches for (i in h) { print h[i]; # print each remaining before line delete h[i]; # delete each line as it's printed } until=NR+after; # record the last after line to print } { if (NR<=until) print $0; # from a match to its last after line: print else h[NR]=$0; # after that: save in history delete h[NR-before]; # remove line too old to be a before line } END {exit !until} # exit status: 0 if there was a match, else 1 

Запустите его как grep-ac -vpattern=PATTERN -vbefore=NBEFORE -vafter=NAFTER где PATTERN – это шаблон для поиска ( расширенное регулярное выражение с несколькими дополнениями awk ), а NBEFORE и NAFTER – это количество строк для печати до и после матча соответственно (по умолчанию 0). Пример:

 <input_file grep-ac -vbefore=2 -vpattern='foo *bar' 

Оказывается, довольно сложно эмулировать -B из-за проблем, возникающих при прямом сопоставлении строк друг за другом. Это в значительной степени запрещает использование любого типа однопроходного сканирования файлов.

Я понял это, играя со следующим приближением:

 perl -pe 'if(/search_term/) {print foreach @A; print ">"; $B=4}; shift @A if push(@A, $_)>7; $_ = "" unless ($B-- > 0);' target_file 

Это будет работать примерно так же, как и grep -A7-B3, с оговоркой, описанной в первом абзаце.

Альтернативным (также однофайльным) решением этой проблемы является использование perl для подачи sed командной строки:

 sed -n `perl -pe '$_=(/search_term/?sprintf("%d,%dp;", $.-3,$.+4):"")' file` file 

Используя sed вы можете сначала получить номера строк совпадающих строк, уменьшать и увеличивать заданный номер строки в цикле while, а затем использовать sed -n "n1,n2p" для печати строк ведущего ( n1 ) и конечного ( n2 ) контекста ( n2 ) аналогично альтернативе sed предложенной пользователем455). Однако многие процессы чтения могут привести к успеху.

ed может напрямую ссылаться на предыдущую и следующие строки согласованной строки, но сбой, если указанный диапазон строк не существует; например, совпадающая строка – это строка номер 2, но должны быть напечатаны 5 строк перед матчем. Поэтому, используя ed необходимо добавить соответствующее количество (пустых) строк в начале и в конце. (Для огромных файлов ed возможно, не лучший инструмент, см.: Bfs – большой файловый сканер ).

 # sample code to match lines with number 5 plus previous & following line # (using Bash) printf '%s\n' {1..20} > num.txt # sed sed -n '/5/=' num.txt | while read num; do n1=$((num - 1)) n2=$((num + 1)) [[ $n1 -lt 1 ]] && n1=1 sed -n "${n1},${n2}p" num.txt echo -- done | sed -e '${/^--$/d;}' # ed cat <<-'EOF' | ed -s num.txt | sed -e $'N;N;a\\\n--' | sed -e '${/^--$/d;}' H 0i beginning: added line one . $a end: added line one . ,g/5/km\ 'm-1,'m+1p q EOF 
  • Необходимо удалить - (минус) знак в конце в количестве из многих столбцов и вставить его на удаленные столбцы
  • Замена пустого пространства без нуля
  • команда sed для обмена символами
  • Считайте уникальные связанные значения в awk (или perl)
  • Чтобы улучшить это регулярное выражение о разделении цифр
  • как предупреждать о пользовательских квотах пользователя ftp в оболочке / sbin / nologin?
  • Невозможно запустить Perl-код как скрипт CGI
  • Объединение строк с общими значениями
  • извлечь столбец из большого текстового файла
  • Как написать эту замену с условием
  • Linux эквивалентен удалению PowerShell «один ко многим»
  • Interesting Posts

    Разрешения монтирования в Linux

    Различные результаты OS X / Linux с «find PATH -mount \ (-type f -o-type d \) -print0 | LC_ALL = C sort –zero-terminated> OUTPUT.txt "

    Вставьте новую строку после разбитой последовательности чисел awk / unix / shell scripting

    apt-get update не удалось разрешить адреса

    Файловая система и макет журнала

    Как изменить имя приложения emacs из «Emacs» на другое в OSX?

    Сделать вкладку «Баш». Автозаполнение соответствует «Содержит» во всех возможных файлах вместо «Начиная с»,

    Насколько разумно делать надёжную работу над системами с ограничительной umask?

    Bash присоединяется к файлу, удаляется во время выполнения. Можно ли это исправить?

    Какой процесс / программа создает / записывает файл, к которому перенаправляется ввод-вывод?

    Проверьте связанные имена файлов и удалите один из них

    Подстановка строк в очень большом файле

    Как получить более точную информацию о завершении работы программы?

    udev не хочет запускать chgrp и chmod

    Я получаю эту ошибку при попытке установить новейшую версию Python 3. Есть идеи, как это исправить?

    Linux и Unix - лучшая ОС в мире.