Как получить часть файла после строки, которая соответствует выражению grep? (первый матч)
у меня есть файл с 1000 строк. Мне нужна часть моего файла после строки, которая соответствует моему заявлению grep.
т. е.
$ cat file | grep 'TERMINATE' // Its found on line 534
Итак, я хочу файл из строки 535 to line 1000 для дальнейшей обработки.
Как мне это сделать ?
12 ответов:
ниже будет напечатана строка соответствия
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до конца ввода.Edit:
если вы хотите строки перед
TERMINATE:sed -e '/TERMINATE/,$d'и если вы хотите, чтобы обе линии до и после
TERMINATEв 2 разных файлах за один проход:sed -e '1,/TERMINATE/w before /TERMINATE/,$w after' fileфайлы до и после будут содержать строку с terminate, поэтому для обработки каждого из них вам нужно использование:
head -n -1 before tail -n +2 afterEdit2:
если вы не хотите, чтобы жестко кодировать имена файлов в скрипте sed, вы можете:
before=before.txt after=after.txt sed -e "1,/TERMINATE/w $before /TERMINATE/,$w $after" fileно тогда вы должны бежать
$означает последнюю строку, поэтому оболочка не будет пытаться расширить$wпеременная (обратите внимание, что теперь мы используем двойные кавычки вокруг скрипта вместо одинарных кавычек).я забыл сказать, что новая строка важна после имен файлов в скрипте, так что sed знает, что имена файлов заканчиваются.
Edit: 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если они содержат текст, который вы хотите заменить с переменной.- The
sedдиапазоны также содержать$и сразу же следуют письма, как:$p,$d,$w. Они также будут выглядеть как переменные для будьте расширены, так что вы должны избежать тех$символы с обратной косой чертой [\] как:$p,$d,$w.
в качестве простого приближения можно использовать
grep -A100000 TERMINATE fileкоторый greps для
TERMINATEи выводит до 100000 строк после этой строки.из man page
-A NUM, --after-context=NUMпечатать число строк из источника данных после сопоставления строк. Помещает строку, содержащую разделитель групп ( -- ) между смежные группы совпадений. С-О или --только-соответствуя вариант, это не имеет никакого эффекта и дается предупреждение.
инструмент для использования здесь awk:
cat file | awk 'BEGIN{ found=0} /TERMINATE/{found=1} {if (found) print }'Как это работает:
- мы устанавливаем переменную 'found' в ноль, оценивая false
- если совпадение для 'TERMINATE' найдено с регулярным выражением, мы устанавливаем его в один.
- если наша переменная' found ' имеет значение True, print:)
другие решения могут потреблять много памяти, если вы используете их на очень большие файлы.
используйте расширение параметра bash следующим образом:
content=$(cat file) echo "${content#*TERMINATE}"
если я правильно понимаю ваш вопрос, вы хотите, чтобы строки после
TERMINATE, не включаяTERMINATE-лайн.awkможно сделать это простым способом:awk '{if(found) print} /TERMINATE/{found=1}' your_fileобъяснение:
- хотя это не лучшая практика, вы можете полагаться на то, что все значения vars по умолчанию равны 0 или пустой строке, если она не определена. Итак, первое выражение (
if(found) print) не будет печатать ничего, чтобы начать С.- после того, как печать сделать, мы проверяем если это стартер-линия (которая не должна быть включена).
это будет печатать все строки после the
TERMINATE-лайн.
обобщение:
- у вас есть файл с start и конец-линии и вы хотите, чтобы линии между этих строк кроме the start- и конец-линии.
- 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 $объяснение:
- если конец - линия найдена никакая печать не должна быть сделана. Обратите внимание, что эта проверка выполняется до фактическая печать для исключения конец - строка из результат.
- вывести текущую строку, если
foundустановлен.- если start - строка найдена, а затем установлена
found=1чтобы напечатать следующие строки. Обратите внимание, что эта проверка выполняется после фактическая печать для исключения startстроки из результата.Примечания:
- код полагается на то, что все 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требуется 2 процесса, чтобы сделать то, что sed может сделать в одном процессе, и если файл изменяется между выполнением grep и tail, результат может быть некогерентным, поэтому я рекомендую использовать sed. Кроме того, если файл не донес содержать
TERMINATE1-я команда не выполняется.
есть много способов сделать это с
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' file
- намного, намного быстрее, чем sed, особенно работая над действительно большим файлом. Он работает до 10 м линий (или все, что вы вставляете), поэтому нет вреда в том, чтобы сделать это достаточно большим, чтобы справиться со всем, что вы ударили.
альтернативы отличный
sedответ jfgagne, и которые не включают соответствующую строку:
awk '/TERMINATE/ {y=1;next} y'( https://stackoverflow.com/a/18166628 )awk '/TERMINATE/ ? c++ : c'( https://stackoverflow.com/a/23984891 )perl -ne 'print unless 1 .. /TERMINATE/'( https://stackoverflow.com/a/18167194 )
Это может быть один из способов сделать это. Если вы знаете, какая строка файла у вас есть слово grep и сколько строк у вас в файле:
grep-A466 'TERMINATE' file
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 }'` tail -n +$LINE_NUMBER $YOUR_FILE_NAME
Comments