I want to move lines matching certain pattern from file1 to file2. Analogous to operation cut and paste from one file to another in windows
I like the other answers, but just an (obvious) alternative approach in case you are worried about making a mistake in your pattern and want an easy way to rollback:
grep 'bar' file1 > file2
grep -v 'bar' file1 > file3
Once you're happy with your results (hint: tee
instead of >
will allow you to see what's getting written to your files):
mv file3 file1
Generally I prefer perl to do substitution like in the above answer, but when the regex idiom gets too complicated and you are semi-blindly copying and pasting commands you don't understand, you're not in control of your precious data.
This might work for you (GNU sed):
sed -i -e '/bar/{w file2' -e 'd}' file1
An alternative:
sed -i -e '/bar/w file2' -e '//d' file1
To append to file2, write to a temporary file and use cat to append at the end of file in a bash script, or use:
sed -i -e '/bar/w tmpfile' -e '$e cat tmpfile >> file2 && rm tmpfile' -e '//d' file1
N.B. For the last solution, only one input file can be modified at a time.
You can use perl and select a different filehandle based in a match of a regular expression when printing:
perl -i.bak -ne 'BEGIN { open $oh, q|>|, pop or die } { print { m/bar/ ? $oh : q|ARGVOUT| } $_ }' file1 file2
It yields:
==> file1 <==
bla foo bla
bla aaa bla
bla foo bla
==> file2 <==
bla bar bla
bla bar bla
You can put a &&
between the two commands to make them a single line. But that won't be more readable, so I don't recommend you do that.
To do the same in one command, you would need something that can edit a file in-place, removing lines you don't want and at the same time printing those lines to stdout
or stderr
so you could redirect it to the other file.
Maybe ed
can do this but I don't know how to write that.
I don't think there is another "standard" UNIX tool to do this.
Btw, cut & paste actually has 3 steps:
The 2-step UNIX command does it without a clipboard.
This awk
script will do the trick:
awk '{a[NR]=$0}END{for(i=1;i<=NR;i++)print a[i] > "file"(a[i]~/bar/?2:1)}' file1
Outputs:
$ cat file1
bla foo bla
bla aaa bla
bla foo bla
$ cat file2
bla bar bla
bla bar bla