Grep поиск строк с переносами строк - PullRequest
9 голосов
/ 07 декабря 2009

Как использовать grep для вывода вхождений строки 'export to excel' во входные файлы, указанные ниже? В частности, как обрабатывать разрывы строк, которые происходят между строками поиска? Есть ли в grep переключатель, который может выполнить эту или какую-то другую команду, вероятно?

Входные файлы:

Файл a.txt:

бла-бла ... экспорт в
Excel ...
бла-бла ..

Файл b.txt:

бла-бла ... экспорт в Excel ...
бла-бла ..

Ответы [ 5 ]

6 голосов
/ 07 декабря 2009

Вы просто хотите найти файлы, которые содержат шаблон, игнорируя разрывы строк, или вы действительно хотите видеть совпадающие строки?

Если первое, вы можете использовать tr для преобразования новых строк в пробелы:

tr '\n' ' ' | grep 'export to excel'

Если последнее, вы можете сделать то же самое, но вы можете использовать флаг -o только для печати фактического соответствия. Затем вы захотите настроить свое регулярное выражение так, чтобы оно содержало любой дополнительный контекст, который вы хотите.

2 голосов
/ 07 декабря 2009

Я не знаю, как это сделать в grep. Я проверил справочную страницу на egrep(1), и она не может совпадать с новой строкой в ​​середине.

Мне нравится решение, предложенное @Laurence Gonsalves, об использовании tr(1) для удаления новых строк. Но, как он отметил, печатать совпадающие строки будет сложно, если вы сделаете это таким образом.

Если вы хотите сопоставить, несмотря на новую строку, а затем вывести соответствующие строки, я не могу придумать, как это сделать с помощью grep, но это было бы не слишком сложно в любом из Python, AWK, Perl или Рубин.

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

Это написано в предположении, что / usr / bin / python - это Python 2.x. При желании вы можете изменить скрипт для работы в Python 3.x.

#!/usr/bin/python

import re
import sys

s_pat = "export\s+to\s+excel"
pat = re.compile(s_pat)

def print_ete(fname):
    try:
        f = open(fname, "rt")
    except IOError:
        sys.stderr.write('print_ete: unable to open file "%s"\n' % fname)
        sys.exit(2)

    prev_line = ""
    i_last = -10
    for i, line in enumerate(f):
        # is ete within current line?
        if pat.search(line):
            print "%s:%d: %s" % (fname, i+1, line.strip())
            i_last = i
        else:
            # construct extended line that included previous
            # note newline is stripped
            s = prev_line.strip("\n") + " " + line
            # is ete within extended line?
            if pat.search(s):
                # matched ete in extended so want both lines printed
                # did we print prev line?
                if not i_last == (i - 1):
                    # no so print it now
                    print "%s:%d: %s" % (fname, i, prev_line.strip())
                # print cur line with special marker
                print "-->  %s:%d: %s" % (fname, i+1, line.strip())
                i_last = i
        # make sure we don't match ete twice
        prev_line = re.sub(pat, "", line)

try:
    if sys.argv[1] in ("-h", "--help"):
        raise IndexError # print help
except IndexError:
    sys.stderr.write("print_ete <filename>\n")
    sys.stderr.write('grep-like tool to print lines matching "%s"\n' %
            "export to excel")
    sys.exit(1)

print_ete(sys.argv[1])

РЕДАКТИРОВАТЬ: добавлены комментарии.

Я столкнулся с некоторыми трудностями, чтобы заставить его печатать правильный номер строки в каждой строке, используя формат, подобный тому, который вы получите с grep -Hn.

Это может быть намного короче и проще, если вам не нужны номера строк и вы не возражаете прочесть сразу весь файл в память:

#!/usr/bin/python

import re
import sys

# This pattern not compiled with re.MULTILINE on purpose.
# We *want* the \s pattern to match a newline here so it can
# match across multiple lines.
# Note the match group that gathers text around ete pattern uses a character
# class that matches anything but "\n", to grab text around ete.
s_pat = "([^\n]*export\s+to\s+excel[^\n]*)"
pat = re.compile(s_pat)

def print_ete(fname):
    try:
        text = open(fname, "rt").read()
    except IOError:
        sys.stderr.write('print_ete: unable to open file "%s"\n' % fname)
        sys.exit(2)

    for s_match in re.findall(pat, text):
        print s_match

try:
    if sys.argv[1] in ("-h", "--help"):
        raise IndexError # print help
except IndexError:
    sys.stderr.write("print_ete <filename>\n")
    sys.stderr.write('grep-like tool to print lines matching "%s"\n' %
            "export to excel")
    sys.exit(1)

print_ete(sys.argv[1])
1 голос
/ 05 мая 2012

grep -A1 "экспорт в" имя файла | grep -B1 "excel"

0 голосов
/ 07 декабря 2009

Я немного проверил это, и, кажется, работает:

sed -n '$b; /export to excel/{p; b}; N; /export to\nexcel/{p; b}; D' filename

Вы можете разрешить дополнительное пространство в конце и начале строк, например:

sed -n '$b; /export to excel/{p; b}; N; /export to\s*\n\s*excel/{p; b}; D' filename
0 голосов
/ 07 декабря 2009

используйте gawk. установите разделитель записей как excel, затем проверьте «экспорт в».

gawk -vRS="excel" '/export.*to/{print "found export to excel at record: "NR}' file

или

gawk '/export.*to.*excel/{print}
/export to/&&!/excel/{
  s=$0
  getline line
  if (line~/excel/){
   printf "%s\n%s\n",s,line
  } 
}' file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...