Перемещение строк, соответствующих шаблону из одного файла в другой

Я хочу переместить строки, соответствующие определенному шаблону, из файла1 в файл2. Аналогично операции вырезания и вставки из одного файла в другой в windows

Пример

скажем, я хочу вырезать все строки, контактирующие с bar из файла1, и вставить его во вновь созданный файл2

Input:

файл1

bla foo bla
bla bar bla
bla aaa bla
bla bar bla
bla foo bla

Желаемый результат после обработки:

файл1

bla foo bla
bla aaa bla
bla foo bla

файл2

bla bar bla
bla bar bla

Что я пробовал

grep создает желаемый файл2, но не изменяет file1

grep 'bar' file1 > file2

sed -i изменяет желаемый файл1, но не создает файл2

sed -i '/bar/d' file1

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

Ваша помощь будет оценена.

Ответ 1

Это может сработать для вас (GNU sed):

sed -i -e '/bar/{w file2' -e 'd}' file1

Альтернатива:

sed -i -e '/bar/w file2' -e '//d' file1

Ответ 2

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

perl -i.bak -ne 'BEGIN { open $oh, q|>|, pop or die } { print { m/bar/ ? $oh : q|ARGVOUT| } $_ }' file1 file2

Это дает:

==> file1 <==
bla foo bla
bla aaa bla
bla foo bla

==> file2 <==
bla bar bla
bla bar bla

Ответ 3

Этот awk script выполнит трюк:

awk '{a[NR]=$0}END{for(i=1;i<=NR;i++)print a[i] > "file"(a[i]~/bar/?2:1)}' file1

Выходы:

$ cat file1
bla foo bla
bla aaa bla
bla foo bla

$ cat file2
bla bar bla
bla bar bla

Ответ 4

Вы можете поместить && между двумя командами, чтобы сделать их одной строкой. Но это не будет более читаемым, поэтому я не рекомендую вам это делать.

Чтобы сделать то же самое в одной команде, вам понадобится что-то, что может редактировать файл на месте, удаляя ненужные строки и в то же время печатать эти строки до stdout или stderr, чтобы вы могли перенаправить его в другой файл. Может быть, ed может это сделать, но я не знаю, как это написать. Я не думаю, что для этого есть еще один "стандартный" UNIX-инструмент.

Btw, вырезать и вставлять на самом деле имеет 3 шага:

  • Скопировать выделенный текст в буфер обмена
  • Удалить из исходного файла
  • Вставить из буфера обмена в новый файл

Двухэтапная команда UNIX делает это без буфера обмена.

Ответ 5

Мне нравятся другие ответы, но просто (очевидный) альтернативный подход на случай, если вы беспокоитесь о том, чтобы совершить ошибку в своем шаблоне и хотите облегчить откат:

grep    'bar' file1 > file2
grep -v 'bar' file1 > file3

Как только вы будете довольны своими результатами (подсказка: tee вместо > позволит вам увидеть, что нужно записать в ваши файлы):

mv file3 file1

Обычно я предпочитаю perl делать подстановку, как в приведенном выше ответе, но когда идиома регулярного выражения становится слишком сложной, и вы не слепо копируете и вставляете команды, которые вы не понимаете, вы не контролируете свои драгоценные данные.