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

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

т.е.

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

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

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

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

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

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

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

 sed -e '1,/TERMINATE/d' 

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

Редактировать:

Если вам нужны строки перед 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, вы можете:

 before=before.txt after=after.txt sed -e "1,/TERMINATE/w $before /TERMINATE/,\$w $after" file того, как before=before.txt after=after.txt sed -e "1,/TERMINATE/w $before /TERMINATE/,\$w $after" file 

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

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

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

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

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

 matchtext=TERMINATE before=before.txt after=after.txt sed -e "1,/$matchtext/w $before /$matchtext/,\$w $after" file того, как 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" 

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

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

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

 grep -A100000 TERMINATE file 

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

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

-A NUM, --after-context=NUM

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

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

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

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

  1. Мы устанавливаем переменную ‘found’ равной нулю, вычисляя false
  2. если совпадение «TERMINATE» найдено с регулярным выражением, мы устанавливаем его в единицу.
  3. Если наша «найденная» переменная имеет значение True, напечатайте 🙂

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

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

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

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

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

Объяснение:

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

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


Обобщение:

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

Пример:

 $ 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 $ 

Объяснение:

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

Заметки:

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

Если по какой-либо причине вы хотите избежать использования 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 может сделать в одном процессе, и если файл изменяется между выполнением grep и tail, результат может быть некогерентным, поэтому я рекомендую использовать sed. Более того, если файл не содержит TERMINATE , команда 1 не работает.

Есть много способов сделать это с помощью 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 

grep -A 10000000 «TERMINATE» файл

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

Альтернативы отличному ответу sed jfgagne и которые не include соответствующую строку:

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

grep -A466 “TERMINATE” файл

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

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

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

Они будут печатать все строки из последней найденной строки «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 
  • Как выполнить команду для каждой строки файла?
  • Лучший способ заменить многие строки - обфускация в C #
  • Эффективный способ сравнения строк версии в Java
  • Выключение строки C ++
  • Изменение строковых констант?
  • Скрыть ввод в командной строке
  • Замена строк в java, аналогично шаблону скорости
  • Разделение строки Java удалено пустым значением
  • Строка макроопределения
  • Получить индекс n-го вхождения строки?
  • Неизменяемый class?
  • Interesting Posts
    Давайте будем гением компьютера.