Grep Access Несколько строк, найти все слова между двумя шаблонами

Нужна помощь в сканировании текстовых файлов и найти все слова между двумя шаблонами. Например, если у нас есть .sql файл, вам нужно отсканировать и найти все слова между "и" где ". Греп может сканировать только одну строку за раз. Для этого требования используется лучший unix script для использования? sed, awk имеет эти функции? Важно отметить любые примеры.

Ответ 1

У Sed есть следующее:

sed -n -e '/from/,/where/ p' file.sql

Печать всех строк между строкой с помощью from и строки с where.

Для чего-то, что может включать строки, которые имеют как из, так и где:

#!/bin/sed -nf

/from.*where/ {
    s/.*\(from.*where\).*/\1/p
    d
}
/from/ {
    : next
    N
    /where/ {
        s/^[^\n]*\(from.*where\)[^\n]*/\1/p
        d
    }
    $! b next
}

Это (написано как sed script) немного сложнее, и я попытаюсь объяснить детали.

Первая строка выполняется в строке, содержащей как from, так и where. Если строка соответствует этому шаблону, выполняются две команды. Мы используем команду s substitute, чтобы извлекать только части между от и где (включая from и where). Суффикс p в этой команде печатает строку. Команда delete очищает пространство шаблонов (рабочий буфер), загружает следующую строку и перезапускает script.

Вторая команда начинает выполнение ряда команд (сгруппированных по фигурным скобкам), когда найдена строка, содержащая from. В принципе, команды образуют цикл, который будет содержать строки добавления из ввода в пространство шаблонов до тех пор, пока не будет найдена строка с where или пока мы не дойдем до последней строки.

Команда : создает ярлык, маркер в script, который позволяет нам "прыгать" назад, когда захочет. Команда N считывает строку из ввода и добавляет ее в пространство шаблонов (разделение строк на символ новой строки).

Когда найдено where, мы можем распечатать содержимое пространства шаблонов, но сначала мы должны очистить его с помощью команды substitute. Он аналогичен используемому ранее, но теперь мы заменяем ведущий и конечный .* на [^\n]*, который сообщает sed, чтобы он соответствовал только символам, отличным от символа новой строки, эффективно сопоставляя a из в первой строке и где в последнем линия. Затем команда d очищает пространство шаблонов и перезапускает script на следующей строке.

Команда b переместится на метку, в нашем случае, на метку next. Однако адрес $! говорит, что он не должен выполняться в последней строке, что позволяет нам выйти из цикла. Если оставить этот цикл таким образом, мы не нашли соответствующий where, поэтому вы можете не печатать его.

Заметьте, однако, это имеет некоторые недостатки. Следующие случаи не будут обрабатываться, как ожидалось:

from ... where ... from

from ... from
where

from
where ... where

from
from
where
where

Для обработки этих случаев требуется больше кода.

Надеюсь, что это поможет =)

Ответ 2

С GNU awk, чтобы вы могли установить RS в RE:

gawk -v RS='[[:space:]]+' '
   /where/ { found=0 }
   found   {  print  }
   /from/  { found=1 }
' file

Вышеизложенное предполагает, что вы не хотите, чтобы напечатанные "от" и "where" были напечатаны, при необходимости перемещайте строки, чтобы сделать это иначе.

В случае, если это помогает, следующие идиомы описывают, как выбрать диапазон записей определенный шаблон для соответствия:

a) Распечатайте все записи из некоторого шаблона:

awk '/pattern/{f=1}f' file

b) Распечатайте все записи после некоторого шаблона:

awk 'f;/pattern/{f=1}' file

c) Распечатайте N-ю запись после некоторого шаблона:

awk 'c&&!--c;/pattern/{c=N}' file

d) Распечатайте каждую запись, кроме N-й записи, после некоторого шаблона:

awk 'c&&!--c{next}/pattern/{c=N}1' file

e) Распечатайте N записей после некоторого шаблона:

awk 'c&&c--;/pattern/{c=N}' file

f) Распечатайте каждую запись, кроме N записей, после некоторого шаблона:

awk 'c&&c--{next}/pattern/{c=N}1' file

g) Распечатайте N записей из некоторого шаблона:

awk '/pattern/{c=N}c&&c--' file

Я изменил имя переменной из "f" для "found" на "c" для "count", где подходящий, поскольку это более выразительно, что переменная на самом деле есть.

Ответ 3

Вы можете использовать ed для этого, он позволяет использовать положительные и отрицательные смещения для диапазона регулярных выражений. Если вход:

seq 10 | tee > infile
1
2
3
4
5
6
7
8
9
10

Труба в команде ed:

<<< /3/,/6/p | ed -s infile

то есть. напечатайте все между строками, содержащими 3 и 6.

Результат:

3
4
5
6

Чтобы получить еще одну строку на каждом конце:

<<< /3/-1,/5/+1p | ed -s infile

Результат:

2
3
4
5
6
7

Или наоборот:

<<< /3/+1,/6/-1p | ed -s infile

Результат:

4
5

Ответ 4

Я смог выполнить это, используя только grep:

#> grep -A#### "start pattern" file | grep -B#### "end pattern"

Проблема заключалась в том, что мне пришлось найти нужное количество строк для включения в опции A и B, которые являются одинаковыми. Надеюсь, что это поможет

Ответ 5

Чтобы вернуть только строку в пределах двух заданных строк по строкам awk (без сумасшествия), я просто запустил эту очень плоскую script, многословность на буксире:

.\gnucoreutils\bin\awk "{startstring = \"RETURN STUFF AFTER ME \"; endstring = \"RETURN STUFF BEFORE ME\"; endofstartstring = index($0,startstring)+length(startstring); print substr($0,endofstartstring,index($0,endstring)-endofstartstring)}" /dev/stdin

Обратите внимание, что я использую cmd.exe (интерпретатор команд с Windows) и gnuwin32 awk, поэтому учитывайте "двойные кавычки" и ^\escape-символы ^ \:

GNU Awk 3.1.6
Copyright (C) 1989, 1991-2007 Free Software Foundation.

Пожалуйста, укажите недостатки.

Пример:

echo "hello. RETURN STUFF AFTER ME i get returned RETURN STUFF BEFORE ME my face is melting" | .\gnucoreutils\bin\awk "{startstring = \"RETURN STUFF AFTER ME \"; endstring = \" RETURN STUFF BEFORE ME\"; endofstartstring = index($0,startstring)+length(startstring); print substr($0,endofstartstring,index($0,endstring)-endofstartstring)}" /dev/stdin
i get returned