Intereting Posts
gnome desktop делает автоматические звуки озвучивания? Как использовать преобразование ImageMagick для масштабирования изображения, добавляя почтовый ящик для получения результата с фиксированным размером? Шифрование файлов (закрытый ключ и т. Д.) Во встроенной системе Как проверить, какая версия vncserver установлена ​​на моем компьютере? открыть (1) в rifle.conf для рейнджера на OS X цвета vim не загружаются автоматически (вероятный конфликт Vundle) Воспроизведение видео в формате ogg с использованием gstreamer во встроенной системе Как определить и преобразовать текущее время в течение нескольких секунд, прошедших в течение текущего дня? В чем причина изменения имени известных приложений? Вопрос по установке IPtables Папки мониторинга, установленные через SSHFS Linux эквивалентен удалению PowerShell «один ко многим» dpkg видит их, но apt-get не может их удалить? скрипт bash для ранжирования файлов на основе сортировки столбца Как отобразить пакеты Yum Local Repo в древовидных структурах на основе зависимости?

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

grep -A 2 -B 3 

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

 grep -C 3 

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

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

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

 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