Як надрукувати всі рядки після збігу до кінця файлу?


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 як відповідати та друкувати рядки?


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

Відповіді:


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

Вбудовану клавішу і вирізання знайдіть перший рядок, що містить візерунок з file2, цей рядок плюс один передається в хвіст, плюс один є, щоб пропустити рядок з малюнком.

Якщо ви хочете почати з останнього матчу замість першого, це буде:

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

Зауважте, що не всі версії хвоста підтримують додаткові позначення.


Це перший приклад команд n і p в sed, які я бачив, що не хочеться занадто далеко забирати 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 рядків у поза контекст (незалежно від вказаного значення).
ruvim

22

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

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

Коли дзвонить із -nпрапором, sedне друкує за замовчуванням рядки, які він більше обробляє. Потім ми використовуємо форму 2-адрес, яка говорить про те, щоб застосувати команду з відповідності рядків /dog 123 4335/до кінця файлу (представлений символом $). Команда p, про яку йдеться , яка друкує поточний рядок. Отже, це означає "надрукувати всі рядки з однієї, що відповідає, /dog 123 4335/до кінця".


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

1
Це виглядає як найкраща відповідь (і працює на мій власний випадок), але її потрібно адаптувати, щоб пропустити відповідну лінію.
Павло Шимерда

1
sed -n '/ собака 123 4335 /, $ p' | sed '1d' видалить собачу лінію
Kemin Zhou

1
sed -n '/dog 123 4335/,$p' | tail -n +2також зніме матч
gilad mayani

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.
брандізі

3
розумний на терміналі, але він насправді не працює, якщо ви підключите його до чогось іншого tac.
jcomeau_ictx

я використовую це так, $ more + / "відповідає моїм словам" file1 >> file2
AMB

1
Може бути +замінено на -pPOSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html, але ще не реалізовано в util-linux 2.20.1. І це також друкує skipping..і деякі зайві нові рядки (на складніше я очікую, так що може бути добре).
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

може, справи змінилися відтоді? мій коментар отримав 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

Якщо вхід є lseekable звичайного файлу:

З 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 / -mопція припинить введення в матчі - і він залишить свій (можна побачити) вхід fd одразу після того, як точка знайшла останню відповідність. Таким чином, виклик grepw / -m1знаходить перше виникнення шаблону у файлі і залишає вхід зміщеним в точно потрібному місці, catщоб записати все, що слідує за першим збігом шаблону, у файл для stdout.

Навіть без 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 у рядок here; команда друку обмежена діапазоном на один після ( +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 прямо не заборонено, ось моя пропозиція припустити, що "cat" - це відповідність.

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


Напевно, нам тут потрібен комітет, щоб прийняти рішення.
poige

1
@poige: так, ти ж відповідь надаєш менш вичерпно
Thor

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