Не объединяйте контекст непрерывных совпадений с grep - PullRequest
8 голосов
/ 28 мая 2011

Если я запускаю grep -C 1 match для следующего файла:

a
b
match1
c
d
e
match2
f
match3
g

, я получаю следующий вывод:

b
match1
c
--
e
match2
f
match3
g

Как видите, поскольку контекст вокруг смежных совпадений«match2» и «match3» перекрываются, они объединяются.Однако я бы предпочел получить одно описание контекста для каждого совпадения, возможно, дублируя строки из входных данных в отчете о контексте.В этом случае я хотел бы получить:

b
match1
c
--
e
match2
f
--
f
match3
g

Каков наилучший способ добиться этого?Я бы предпочел решения, которые являются достаточно общими, чтобы их можно было легко адаптировать к другим grep вариантам (различные значения для -A, -B, -C или совершенно другие флаги).В идеале я надеялся, что есть умный способ сделать это только с grep ....

Ответы [ 4 ]

3 голосов
/ 26 июля 2011

Я не думаю, что это возможно при использовании простого grep.

Вы когда-нибудь использовали Python?На мой взгляд, это идеальный язык для таких задач (этот фрагмент кода будет работать как для Python 2.7, так и для 3.x):

with open("your_file_name") as f:
   lines = [line.rstrip() for line in f.readlines()]
   for num, line in enumerate(lines):
      if "match" in line:
         if num > 0:
            print(lines[num - 1])

         print(line)

         if num < len(lines) - 1:
            print(lines[num + 1])
            if num < len(lines) - 2:
               print("--")

Это дает мне:

b
match1
c
--
e
match2
f
--
f
match3
g
2 голосов
/ 28 мая 2011

Я не думаю, что это можно сделать с помощью простого grep.

Конструкция sed, представленная ниже, работает в некоторой степени, теперь мне нужно только выяснить, как добавить разделитель "-"

$ sed -n -e '/match/{x;1!p;g;$!N;p;D;}' -e h log
b
match1
c
e
match2
f
f
match3
g
1 голос
/ 28 июля 2011

Я бы предложил исправить патч grep вместо того, чтобы обходить его.В GNU grep 2.9 в src / main.cpp:

933       /* We print the SEP_STR_GROUP separator only if our output is
934          discontiguous from the last output in the file. */
935       if ((out_before || out_after) && used && p != lastout && group_separator)
936         {
937           PR_SGR_START_IF(sep_color);
938           fputs (group_separator, stdout);
939           PR_SGR_END_IF(sep_color);
940           fputc('\n', stdout);
941         }
942 

Здесь будет достаточно простого дополнительного флага.

Редактировать: Ну, да, конечно, это не так просто, так какgrep не будет воспроизводить контекст, просто добавит еще несколько разделителей.Из-за линейности grep весь патч, вероятно, не так прост.Тем не менее, если у вас есть хорошая версия для патча, это может стоить того.

0 голосов
/ 02 августа 2011

Это не представляется возможным с grep или GNU grep.Однако это возможно при использовании стандартных инструментов POSIX и хорошей оболочки, такой как bash, в качестве рычага для получения желаемого результата.
Примечание: для решения не нужны ни python, ни perl.В худшем случае используйте awk или sed.

Одно из решений, которое я быстро создал на прототипе, выглядит примерно так (оно включает в себя издержки на повторное чтение файла, и это решение зависит от того, допустимы ли эти издержки, иподдавка - это исходный вопрос об использовании -1 в качестве фиксированного числа строк контекста, что позволяет просто использовать head & tail):

$ OIFS="$IFS"; lines=`grep -n match greptext.txt | /bin/cut -f1 -d:`; 
for l in $lines; 
do IFS=""; match=`/bin/tail -n +$(($l-1)) greptext.txt | /bin/head -3`; 
echo $match; echo "---"; 
done; IFS="$OIFS"

Это может иметь некоторый угловой случай, связанный с этим, и этосбрасывает IFS, когда, возможно, нет необходимости, хотя это подсказка для попытки использовать возможности оболочки и инструментов POSIX вместо интерпретатора высокого уровня для получения желаемого результата.

Мнение: Все хорошие операционные системы имеют: grep, awk, sed, tr, cut, head, tail, больше, меньше, vi как встроенные модули.На лучших операционных системах они находятся в /bin.

...