Как распечатать все строки после совпадения до конца файла?


48

Входной файл1:

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Я даю совпадение по шаблону из in other file(как dog 123 4335из file2).

Я соответствую шаблону строки, dog 123 4335и после печати всех строк без строки соответствия мой вывод:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Если использовать только без адреса строки, используйте только шаблон, например, 1s как сопоставить и напечатать строки?


Может ли другой файл содержать только один шаблон для поиска или по одному в строке и начать поиск с той строки, которая найдена первой в искомом файле?
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

Ответы:


27

Предполагая, что вы хотите сопоставить всю строку с вашим шаблоном, с GNU sedэто работает:

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

Стандартный эквивалент:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

Со следующим вводом ( infile):

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Выход:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Объяснение:

  • /^dog 123 4335$/ ищет нужный шаблон.
  • :a; n; p; ba;является циклом, который выбирает новую строку из input ( n), печатает ее ( p) и переходит обратно к метке a :a; ...; ba;.

Обновить

Вот ответ, который приближается к вашим потребностям, то есть шаблон в файле file2, извлеченный из файла file1:

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

Внедренные grep и cut находят первую строку, содержащую шаблон из файла file2, этот номер строки плюс один передается на хвост, плюс один, чтобы пропустить строку с шаблоном.

Если вы хотите начать с последнего матча, а не с первого, это будет:

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

Обратите внимание, что не все версии tail поддерживают добавочную нотацию.


Это первый пример команд n и p в sed, который я видел, который не выглядит слишком сложным. Кажется (из моих кратких тестов), что sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(с переключенными p и n) успешно включает в себя строку, которая также соответствует.
Иосия Йодер

26

Если у вас достаточно короткий файл, он grepможет работать:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

5000 - это мое предположение о «достаточно коротком», так как grepнаходит первое совпадение и выводит его вместе со следующими 5000 строками (файл не должен иметь такого количества). Если вы не хотите совпадения, вам нужно его обрезать, например

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


Если вы не хотите использовать первое, но последнее совпадение в качестве разделителя, вы можете использовать это:

tac animals.txt | sed -e '/dog 123 4335/q' | tac

Эта строка читает animals.txtв обратном порядке строк и выводит до строки включительно dog 123 4335и затем снова переворачивает для восстановления правильного порядка.

Опять же, если вам не нужно совпадение в результате, добавьте хвост. (Вы также можете усложнить выражение sed, чтобы отбросить его буфер перед выходом.)


По моему тесту, GNU grep 3.0 не выводит более 132 строк после контекста (независимо от указанного значения).
Рувим

22

На практике я бы , вероятно , использовать ответ Aet3miirah в большую часть времени и ответ Алексея замечательно , когда требуется перемещаться по линиям (кроме того , он также работает с less). ОТО, мне действительно нравится другой подход (который является своего рода обратным ответом Жиля :

sed -n '/dog 123 4335/,$p'

При вызове с -nфлагом sedне выводит по умолчанию строки, которые обрабатывает больше. Затем мы используем двухадресную форму, в которой говорится, что нужно применить команду от строки, совпадающей /dog 123 4335/до конца файла (представлена $). Рассматриваемая команда pпечатает текущую строку. Таким образом, это означает «печатать все строки от одной совпадающей /dog 123 4335/до конца».


3
Это печатает dogстроку, хотя это не требуется здесь.
Стефан Шазелас

1
Это выглядит как лучший ответ (и работает для моего собственного случая), но его также необходимо адаптировать, чтобы пропустить согласованную линию.
Павел Шимерда

1
sed -n '/ dog 123 4335 /, $ p' | sed '1d' удалит собачью линию
Кемин Чжоу

1
sed -n '/dog 123 4335/,$p' | tail -n +2также удалит матч
Гилад Майани

15
sed -e '1,/dog 123 4335/d' file1

Если вам нужно прочитать шаблон из файла, подставьте его в команду sed. Если файл содержит шаблон sed:

sed -e "1,/$(cat file2)/d" file1

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

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

Если вы хотите, чтобы совпадение представляло собой целую строку, а не просто подстроку, оберните шаблон ^…$.

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1

6
Это не сработает, если шаблон находится на первой строке. У GNU sedесть 0,/dog.../dдля этого.
Стефан Шазелас

14

$ more +/"dog 123 4335" file1


4
Это также работает с less.
brandizzi

3
умный на терминале, но на самом деле он не работает, если вы передадите ему что-то подобное tac.
jcomeau_ictx

я использую это так, $ more + / "соответствовать моим словам" file1 >> file2
AMB

1
Возможно +был заменен -pв POSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html, но еще не реализован в util-linux 2.20.1. И это также печатает skipping..и некоторые дополнительные символы новой строки (я думаю, для stderr, так может быть хорошо).
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

может быть, все изменилось с тех пор? мой комментарий получил 3 голосов, поэтому он мог быть актуальным в то время ...
jcomeau_ictx


5

Один из способов использования awk:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

где file2 содержит ваши шаблоны поиска. Во-первых, все содержимое файла file2 хранится в массиве «a». Когда файл1 обрабатывается, каждая строка проверяется на соответствие массиву и печатается, только если ее нет.


Я думаю, что ОП хочет вывести каждую строку, следующую за шаблоном.
Тор

@Thor: спасибо за указание, обновил сейчас ...
Гуру

Красиво сделано :).
Тор

5

Если ввод является обычным файлом, который можно найти :

С GNU grep:

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

С sed:

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

GNU с grepименем w / -moption завершит ввод во время совпадения и оставит свой (lseekable) ввод fd сразу после точки, в которой было найдено последнее совпадение. Таким образом, вызов grepw / -m1находит первое вхождение шаблона в файле и оставляет входное смещение точно в правильном месте, catчтобы записать все, после первого совпадения шаблона в файле, в стандартный вывод.

Даже без GNU grepвы можете делать то же самое с POSIX-совместимым sed- когда sed qон указан, он оставляет свое входное смещение там, где он делает. Однако GNU sedне соответствует стандартам, поэтому вышеприведенное, скорее всего, не будет работать без GNU, sedесли вы не вызовете его с помощью -uпереключателя.


Обратите внимание, что sedсовместное использование потоков, показанное здесь, не является специально (хотя, да, стандарт, на который делается ссылка, делает конкретный пример sedкак утилита, способная таким образом) для показанного в свободной форме и условно кооперативного рабочего процесса. Примечательно, что все стандартные утилиты предназначены и определены таким образом, чтобы взаимодействовать и совместно использовать позиции курсора входных потоков, не нарушая при дальнейшей обработке следующего считывателя какую-либо обработку. grep -qдолжен сделать это; спокойно grepдолжен вернуться, как только будет найдено какое-либо совпадение на входе, и все оставшиеся входные данные по умолчанию не должны использоваться по умолчанию.
mikeserv

4

Мой ответ на вопрос в теме, без сохранения шаблона во втором файле. Вот мой тестовый файл:

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Вариант Perl с шаблоном в файле:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

2

Wth ed:

ed -s file1 <<< '/dog 123 4335/+1,$p'

Это отправляет одну pкоманду rint в ed-строку; Команда печати ограничена до одного после ( +1) dog 123 4335совпадения до конца файла ( $).


1

Если вы не против создания временного файла, и есть в csplitналичии, это работает:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

Примечание file1- это входной файл и файл file2шаблона (как указано в вопросе).

Длинная форма приведенной выше команды:

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

т.е.

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplitбез указанного prefixвыше флага будет создан файл xx00(с префиксом xxи суффиксом 00). С флагом выше он создает файл file1_00. Без quietфлага печатается размер выходного файла (размер полученного файла).


0

Поскольку awk явно не запрещен, вот мое предложение, предполагая, что «кошка» - это совпадение.

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt

0

Как распечатать все строки после совпадения до конца файла?

Другой способ выразить это «как удалить все строки с 1-й до совпадения (включая)», и это можно sedзаписать так:

sed -e '1,/MATCH PATTERN/d'

1
Единственная проблема заключается в том, когда шаблон находится на первой строке ...
don_crissti


Я думаю, нам нужен комитет, чтобы решить.
Пой

1
@poige: нет, вы предоставляете тот же ответ менее всесторонне
Тор

@don_crissti, что sed -e '0,/MATCH PATTERN/d'тогда?
Велкан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.