Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a file that contains 4n lines. Here is an excerpt from it containing 8 lines

6115 8.88443
6116 6.61875
6118 16.5949
6117 19.4129
6116 6.619 
6117 16.5979 
6118 19.4111
6115 8.88433  

What I want to do is sort a block, where each block consists of 4 lines based on the first column. The output for the excerpt should look as shown below.

6115 8.88443
6116 6.61875
6117 19.4129
6118 16.5949
6115 8.88433 
6116 6.619 
6117 16.5979 
6118 19.4111 
share|improve this question

5 Answers 5

You can do it with Perl:

perl -nle '
   push @a,$_;
   unless($. % 4){
       print join "\n",sort {$a <=> $b} @a; # Sort @a, and print its contents
       @a = (); # Empty @a to start a new block
   }
' your_file

How this works

  • -n --> run the code for each input line (and put the current line in $_)
  • -l --> append a newline to the output of any print
  • -e --> execute the following string as Perl code
  • Each line is appended to the array @a.
  • $. holds the current line number and unless that number is not congruent to zero modulo 4, then we keep working. If it is congruent to zero modulo 4, we have reached a line whose number is a multiple of 4 (the end of a block), in which case, we sort the entries in @a in ascending numerical order and print the entries in the sorted array joined by a newline to standard output.
share|improve this answer

You could use to add an initial serial number that changes every four lines and use that as the primary sorting column

awk '{print int((NR-1)/4), $0}' file.txt | sort -n -k1,1 -k2,2 | cut -f2- -d' '
share|improve this answer
    
This worked thanks –  bouken Nov 11 '13 at 3:28

If this is a one off and you don't want to learn python, perl or awk, you can go with the basic split and sort commands.

First split the file in 4 line chunks with the -l option:

split -a 6 -l 4 input_file my_prefix_
for fn in my_prefix_*; do
    sort -n -o $fn $fn
done
cat my_prefix_* > output_file
rm my_prefix_*

The sort -n sorts by numerical value of the first column (999 before 1234). -a 6 should take care of a file with 26^6*4 lines. my_prefix_ should be something unique to the directory you work with.

share|improve this answer

You can get a clean solution with R. If the table above is in a file called "table.txt", then perform the following steps. The desired result will be in the file "tableout.txt".

> x = read.table("table.txt", col.names=c("a", "b"))
> x
     a        b
1 6115  8.88443
2 6116  6.61875
3 6118 16.59490
4 6117 19.41290
5 6116  6.61900
6 6117 16.59790
7 6118 19.41110
8 6115  8.88433
> x["index"] = c(rep(1, 4), rep(2, 4))
> x
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
3 6118 16.59490     1
4 6117 19.41290     1
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
8 6115  8.88433     2     
> xord = x[with(x, order(index, a)), ]
> xord
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
4 6117 19.41290     1
3 6118 16.59490     1
8 6115  8.88433     2
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
> write.table(xord[,1:2], "tableout.txt", row.names=FALSE, col.names=FALSE)

See also How to sort a dataframe by column(s) in R.

share|improve this answer

Using a Bourne-like shell,

while read a ; do                                           # Try reading a line.
    read b ; read c ; read d                                # OK, read 3 more.
    printf '%s\n%s\n%s\n%s\n' "$a" "$b" "$c" "$d" | sort -n # Sort them.
done < data
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.