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



у меня есть файл с 1000 строк. Мне нужна часть моего файла после строки, которая соответствует моему заявлению grep.



т. е.



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


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



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

597   12  

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 after

Edit2:

если вы не хотите, чтобы жестко кодировать имена файлов в скрипте 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"

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

  1. переменные ($variablename), заключенный в single quotes ['] не будет "расширяться", но переменные внутри double quotes ["] будет. Итак, вы должны изменить все single quotes до double quotes если они содержат текст, который вы хотите заменить с переменной.
  2. 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 }'

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

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

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

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

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

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

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

объяснение:

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

это будет печатать все строки после 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
$

объяснение:

  1. если конец - линия найдена никакая печать не должна быть сделана. Обратите внимание, что эта проверка выполняется до фактическая печать для исключения конец - строка из результат.
  2. вывести текущую строку, если found установлен.
  3. если 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. Кроме того, если файл не донес содержать 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' file

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

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

Это может быть один из способов сделать это. Если вы знаете, какая строка файла у вас есть слово 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

    Ничего не найдено.