Как получить часть файла после строки, которая соответствует выражению grep? (первое совпадение)
У меня есть файл с примерно 1000 строк. Я хочу часть моего файла после строки, которая соответствует моей команде grep.
т.е.
$ cat file | grep 'TERMINATE' // Its found on line 534
Итак, я хочу, чтобы файл с строки 535 to line 1000
для дальнейшей обработки.
- В чем преимущество непрерывности String?
- Операция XOR с двумя строками в java
- Сравнить номера версий без использования функции split
- Строка неизменна. В чем же смысл?
- Удалить расширение файла из строки имени файла
Как мне это сделать ?
- Поиск строки Java, игнорирующий акценты
- Есть ли на C # String Tokenizer, например, Java?
- Преобразование строки в байтовый массив в C #
- Как использовать «.» Как разделитель с String.split () в java
- Как написать символ и в файле android strings.xml
- Формат метода (String, Object ) в типе String не применим для аргументов (...)
- Скрыть ввод в командной строке
- Игнорирование акцентированных букв в сравнении строк
Следующее напечатает строку, соответствующую 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"
Важными моментами замены текста переменными в этих случаях являются:
- Переменные (
$variablename
), заключенные вsingle quotes
['
], не будут «расширяться», но переменные внутриdouble quotes
["
] будут. Таким образом, вы должны изменить всеsingle quotes
наdouble quotes
если они содержат текст, который вы хотите заменить Переменная. - Диапазоны
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 }'
Как это работает:
- Мы устанавливаем переменную ‘found’ равной нулю, вычисляя false
- если совпадение «TERMINATE» найдено с регулярным выражением, мы устанавливаем его в единицу.
- Если наша «найденная» переменная имеет значение True, напечатайте 🙂
Другие решения могут потреблять много памяти, если вы используете их в очень больших файлах.
Используйте расширение параметра bash следующим образом:
content=$(cat file) echo "${content#*TERMINATE}"
Если я правильно понял ваш вопрос, вы хотите, чтобы строки были после TERMINATE
, не включая TERMINATE
-line. awk
может сделать это простым способом:
awk '{if(found) print} /TERMINATE/{found=1}' your_file
Объяснение:
- Хотя это не лучшая практика, вы можете положиться на то, что все vars по умолчанию равны 0 или пустая строка, если она не определена. Таким образом, первое выражение (
if(found) print
) не будет печатать ничего, чтобы начать с. - После завершения печати мы проверяем, является ли это стартовой линией (которая не должна включаться).
Это напечатает все строки после строки 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 $
Объяснение:
- Если конечная линия найдена, печать не должна выполняться. Обратите внимание, что эта проверка выполняется до фактической печати, чтобы исключить конечную строку из результата.
- Распечатайте текущую строку, если
found
. - Если найдена старт- линия, то установите
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 соответствующую строку:
-
awk '/TERMINATE/ {y=1;next} y'
( https://stackoverflow.com/a/18166628 ) -
awk '/TERMINATE/ ? c++ : c'
awk '/TERMINATE/ ? c++ : c'
( https://stackoverflow.com/a/23984891 ) -
perl -ne 'print unless 1 .. /TERMINATE/'
( https://stackoverflow.com/a/18167194 )
Это может быть один из способов сделать это. Если вы знаете, в какой строке файла у вас есть слово 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