Как получить часть файла после строки, которая соответствует выражению 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-миллиметровых линий (или что бы вы ни вкладывали), поэтому никакого вреда в том, чтобы сделать это достаточно большим, чтобы справляться со всем, что вы нанесли.
Ответ 9
Альтернативы отличному ответу sed
jfgagne и которые не включают соответствующую строку:
Ответ 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