Как получить часть файла после строки, которая соответствует выражению grep? (первое совпадение)

У меня есть файл с примерно 1000 строк. Я хочу часть моего файла после строки, которая соответствует моей инструкции grep.

то есть.

$ cat file | grep 'TERMINATE'     // Its found on line 534

Итак, я хочу, чтобы файл из строки 535 to line 1000 для дальнейшей обработки.

Как мне это сделать?

Ответ 1

Далее будет напечатана строка, соответствующая TERMINATE до конца файла:

sed -n -e '/TERMINATE/,$p'

Разъяснение: -n отключает поведение по умолчанию sed для печати каждой строки после выполнения его script на нем, -e указывает script на sed, /TERMINATE/,$ - это выбор диапазона адресов (линий), означающий первую строку, соответствующую правильному выражению TERMINATE (например, grep) в конце файла ($), а p - это команда печати, которая печатает текущую строку.

Это будет печатать из строки, следующей за строкой, соответствующей TERMINATE до конца файла:
(от ПОСЛЕ соответствия линии к EOF, не включая соответствующую строку)

sed -e '1,/TERMINATE/d'

Разъяснение: 1,/TERMINATE/ - это выбор диапазона адресов (линий), означающий первую строку для ввода в 1-ю строку, соответствующую регулярному выражению TERMINATE, а d - команда удаления которые удаляют текущую строку и переходят к следующей строке. Поскольку поведение sed по умолчанию заключается в том, чтобы печатать строки, оно будет печатать строки после TERMINATE до конца ввода.

Edit:

Если вам нужны строки до TERMINATE:

sed -e '/TERMINATE/,$d'

И если вы хотите обе строки до и после TERMINATE в 2 разных файла за один проход:

sed -e '1,/TERMINATE/w before
/TERMINATE/,$w after' file

Файлы до и после будут содержать строку с завершением, поэтому для обработки каждого из них вам нужно использовать:

head -n -1 before
tail -n +2 after

Edit2:

ЕСЛИ вы не хотите жестко закодировать имена файлов в sed script, вы можете:

before=before.txt
after=after.txt
sed -e "1,/TERMINATE/w $before
/TERMINATE/,\$w $after" file

Но тогда вам нужно избежать $, что означает последнюю строку, поэтому оболочка не будет пытаться развернуть переменную $w (обратите внимание, что теперь мы используем двойные кавычки вокруг script вместо одиночных кавычек).

Я забыл сказать, что новая строка важна после имен файлов в script, так что sed знает, что имена файлов заканчиваются.


Изменить: 2016-0530

Себастьян Клеман спросил: "Как бы вы заменили жестко закодированную TERMINATE на переменную?"

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

matchtext=TERMINATE
before=before.txt
after=after.txt
sed -e "1,/$matchtext/w $before
/$matchtext/,\$w $after" file

использовать переменную для соответствующего текста с предыдущими примерами:

## Print the line containing the matching text, till the end of the file:
## (from the matching line to EOF, including the matching line)
matchtext=TERMINATE
sed -n -e "/$matchtext/,\$p"
## Print from the line that follows the line containing the 
## matching text, till the end of the file:
## (from AFTER the matching line to EOF, NOT including the matching line)
matchtext=TERMINATE
sed -e "1,/$matchtext/d"
## Print all the lines before the line containing the matching text:
## (from line-1 to BEFORE the matching line, NOT including the matching line)
matchtext=TERMINATE
sed -e "/$matchtext/,\$d"

Важными моментами замены текста переменными в этих случаях являются:

  • Переменные ($variablename), заключенные в single quotes ['], не будут расширяться, но переменные внутри double quotes ["] будут. Таким образом, вы должны изменить все single quotes на double quotes, если они содержат текст, который вы хотите заменить переменной.
  • Диапазоны sed также содержат $, и за ними сразу следует буква: $p, $d, $w. Они также будут выглядеть как переменные, которые нужно развернуть, поэтому вам нужно избегать этих $ символов с обратным слэшем [\], например: \$p, \$d, \$w.

Ответ 2

В качестве простого приближения вы можете использовать

grep -A100000 TERMINATE file

который greps для TERMINATE и выводит до 100000 строк после этой строки.

Из справочной страницы

-A NUM, --after-context=NUM

Печать NUM строк конечного контекста после сопоставления строк.Помещает строку, содержащую разделитель группы (-) между смежные группы матчей. При использовании -o или -only-matching, это не имеет никакого эффекта, и предоставляется предупреждение.

Ответ 3

Инструмент для использования здесь - awk:

cat file | awk 'BEGIN{ found=0} /TERMINATE/{found=1}  {if (found) print }'

Как это работает:

  • Мы устанавливаем переменную 'found' в ноль, оценивая false
  • Если для "TERMINATE" найдено соответствие с регулярным выражением, мы устанавливаем его в один.
  • Если наша найденная переменная имеет значение True, напечатайте:)

Другие решения могут потреблять много памяти, если вы используете их в очень больших файлах.

Ответ 4

Используйте расширение параметра bash следующим образом:

content=$(cat file)
echo "${content#*TERMINATE}"

Ответ 5

Если я правильно понял ваш вопрос, вам нужны строки после TERMINATE, не включая TERMINATE -line. awk может сделать это простым способом:

awk '{if(found) print} /TERMINATE/{found=1}' your_file

Пояснение:

  • Хотя это не лучшая практика, вы можете положиться на то, что все vars по умолчанию равны 0 или пустая строка, если она не определена. Таким образом, первое выражение (if(found) print) не будет печатать ничего, чтобы начать с.
  • После завершения печати мы проверяем, является ли это стартовой линией (которая не должна включаться).

Это приведет к печати всех строк после строки TERMINATE.


Обобщение:

  • У вас есть файл с стартом - и конец, и вы хотите, чтобы линии между этими строками исключая start - и конец.
  • начать - и конец -линии могут быть определены с помощью регулярного выражения, соответствующего строке.

Пример:

$ cat ex_file.txt 
not this line
second line
START
A good line to include
And this line
Yep
END
Nope more
...
never ever
$ awk '/END/{found=0} {if(found) print} /START/{found=1}' ex_file.txt 
A good line to include
And this line
Yep
$

Пояснение:

  • Если найдена строка end, печать не должна выполняться. Обратите внимание, что эта проверка выполняется до фактической печати, чтобы исключить строку конец из результата.
  • Распечатайте текущую строку, если установлен found.
  • Если строка start найдена, установите found=1 так, чтобы печатались следующие строки. Обратите внимание, что эта проверка выполняется после фактической печати, чтобы исключить строку start из результата.

Примечания:

  • Код полагается на то, что все awk-vars по умолчанию равны 0 или пустая строка, если она не определена. Это действительно, но не может быть лучшей практикой, поэтому вы можете добавить BEGIN{found=0} в начало awk-выражения.
  • Если найдено несколько начальных -блоков, все они напечатаны.

Ответ 6

Если по какой-либо причине вы хотите избежать использования sed, следующее будет печатать строку, соответствующую TERMINATE, до конца файла:

tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file

и следующее будет печатать из следующей строки, соответствующей TERMINATE до конца файла:

tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file

Для одного процесса, который может сделать sed в одном процессе, требуется 2 процесса, и если файл изменяется между выполнением grep и tail, результат может быть некогерентным, поэтому я рекомендую использовать sed. Более того, если файл не содержит TERMINATE, команда 1 не работает.

Ответ 7

Существует много способов сделать это с помощью sed или awk:

sed -n '/TERMINATE/,$p' file

Это ищет TERMINATE в вашем файле и печатает из этой строки до конца файла.

awk '/TERMINATE/,0' file

Это точно такое же поведение, как sed.

Если вы знаете номер строки, из которой вы хотите начать печать, вы можете указать ее вместе с NR (номер записи, который в конечном итоге указывает номер строки):

awk 'NR>=535' file

Пример

$ seq 10 > a        #generate a file with one number per line, from 1 to 10
$ sed -n '/7/,$p' a
7
8
9
10
$ awk '/7/,0' a
7
8
9
10
$ awk 'NR>=7' a
7
8
9
10

Ответ 8

grep -A 10000000 "TERMINATE" файл

  • намного, намного быстрее, чем sed, особенно работающий над действительно большим файлом. Он работает до 10-миллиметровых линий (или что бы вы ни вкладывали), поэтому никакого вреда в том, чтобы сделать это достаточно большим, чтобы справляться со всем, что вы нанесли.

Ответ 10

Это может быть один из способов сделать это. Если вы знаете, в какой строке файла у вас есть слово grep и сколько строк у вас есть в файле:

grep -A466 "TERMINATE" файл

Ответ 11

sed - намного лучший инструмент для работы:   sed -n '/re/, $p' file

где re - регулярное выражение.

Другим вариантом является флаг grep -after-context. Вам нужно передать число, чтобы положить конец, используя wc в файле, чтобы дать нужное значение для остановки. Объедините это с -n и вашим выражением соответствия.

Ответ 12

Они будут печатать все строки из последней найденной строки "TERMINATE" до конца файла:

LINE_NUMBER=`grep -o -n TERMINATE $OSCAM_LOG|tail -n 1|sed "s/:/ \\'/g"|awk -F" " '{print $1}'`
tail -n +$LINE_NUMBER $YOUR_FILE_NAME