0

I have a file like this:

aaa.bbb.1.ccc
xxx.bbb.21
mmm.ppp
xxx.eee
mmm.qqqq
xxx.hhh.12.ddd

I want to move all the lines starting with xxx. at the top of the file with a simple command (using sed, awk, grep...).

So my new file will look like this:

xxx.bbb.21
xxx.eee
xxx.hhh.12.ddd
aaa.bbb.1.ccc
mmm.ppp
mmm.qqqq

How to do this?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
MOHAMED
  • 41,599
  • 58
  • 163
  • 268

6 Answers6

6

One solution:

sed -n '/^xxx/! { H }; // p; $ { x; s/^\n//; p }' infile

The H appends the content that does not begin with xxx to the hold space, and the opposite match is printed inmediatly // p. At last line $ recover the hold space contents, remove leading newline character and print.

It yields:

xxx.bbb.21
xxx.eee
xxx.hhh.12.ddd
aaa.bbb.1.ccc
mmm.ppp
mmm.qqqq
Birei
  • 35,723
  • 2
  • 77
  • 82
4

You can process the file twice with awk:

$ awk 'FNR==NR {if (/^xxx\./) {print; a[FNR]} next} !(FNR in a)' file file
xxx.bbb.21
xxx.eee
xxx.hhh.12.ddd
aaa.bbb.1.ccc
mmm.ppp
mmm.qqqq

In the first one, we match the lines starting with xxx. and: print them, store its number. In the second reading of the file, we just skip those stored lines.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
3

Another awk

awk '!/^xxx/ {a[$0];next} 1; END {for (i in a) print i}' file
xxx.bbb.21
xxx.eee
xxx.hhh.12.ddd
aaa.bbb.1.ccc
mmm.ppp
mmm.qqqq

!/^xxx/ If line does not start with xxx
a[$0];next store it in array a
1 print line with xxx
END {for (i in a) print i} At end print lines in array a. (the one without xxx)


As fedorqui (thank you) points out, if order of lines are important, use this:

awk '!/^xxx/ {a[++c]=$0;next} 1; END {for (i=1;i<=c;i++) print a[i]}' file
xxx.bbb.21
xxx.eee
xxx.hhh.12.ddd
aaa.bbb.1.ccc
mmm.ppp
mmm.qqqq
Jotne
  • 40,548
  • 12
  • 51
  • 55
  • note this maybe does not preserve the order ([your own question!](http://stackoverflow.com/q/20683474/1983854)) – fedorqui Mar 04 '15 at 11:04
3

Another awk for those not in the mood to use arrays:

$ awk 'NR == FNR { if (/^xxx/) print; next } !/^xxx/' top.txt top.txt
xxx.bbb.21
xxx.eee
xxx.hhh.12.ddd
aaa.bbb.1.ccc
mmm.ppp
mmm.qqqq

NR == FNR { if (/^xxx/) print; next } First pass, print lines starting with xxx
!/^xxx/ Second pass, print lines not starting with xxx

jas
  • 10,715
  • 2
  • 30
  • 41
  • You can write this `top.txt top.txt` like this `top.txt{,}` – Jotne Mar 04 '15 at 11:04
  • @jas, Why do you need to equate NR==FNR? Can you please explain the purpose of it – Sadhun Mar 04 '15 at 13:01
  • 1
    Sure, @Sadhun, it's actually quite well explained here: http://backreference.org/2010/02/10/idiomatic-awk/ (search for the section headed "Two-file processing"). In this case, of course, instead of process two files we're processing the same file twice (putting the file on the command line twice). As `NR` is the total number of recs read by awk until this point, and `FNR` is the number of recs within the current file, when `NR == FNR` we know we are reading the file for the first time. The `next` keps awk from going to the next statement, which therefore can only be reached on second readng – jas Mar 04 '15 at 13:34
  • @jas - I got the answer. NR==FNR will run the first operation in first file and once fails it goes for next operation in second file – Sadhun Mar 04 '15 at 13:51
2

With grep:

grep "^xxx" File > NewFile && grep -v "^xxx" File >> NewFile

Redirect all lines starting with xxx to file NewFile. Then grep for lines not starting with xxx and append to NewFile.

It uses && between commands, so that one is not executed if the former exited with the bad status.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Arjun Mathew Dan
  • 5,240
  • 1
  • 16
  • 27
  • you probably want to say `&&` instead of `;`. This way, the final `mv tmp File` won't be done if something failed before. Otherwise, you may end up truncating `File`. – fedorqui Mar 04 '15 at 10:10
  • 1
    or `{ grep ; grep ; } > NewFile`. Bad new is 2 subshell at least but very fast on huge file – NeronLeVelu Mar 04 '15 at 12:03
1
sed '/^xxx/!{H;$!d;}
     ${x;s/.//;}' YourFile

using the d behaviour (cycle without going further in script)

NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43