Solomon
Solomon

Reputation: 189

Sort the tab-delimited numbers on each line of a file

I'm trying to sort the numbers on each line of a file individually. The numbers within one line are separated by tabs. (I used spaces but they're actually tabs.)

For example, for the following input

5 8 7 6 
1 5 6 8
8 9 7 1

the desired output would be:

5 6 7 8
1 5 6 7
1 7 8 9

My attempt so far is:

let i=1
while read line
do
    echo "$line" | tr "    " "\n" | sort -g
    cut -f $i fileName | paste -s >> tempFile$$
    ((++i))
done < fileName

Upvotes: 1

Views: 546

Answers (5)

Akshay Hegde
Akshay Hegde

Reputation: 16997

Using awk

$ cat file
5 8 7 6 
1 5 6 8
8 9 7 1

$ awk '{c=1;while(c!=""){c=""; for(i=1;i<NF;i++){n=i+1; if($i>$n){c=$i;$i=$n;$n=c}}}}1' file
5 6 7 8
1 5 6 8
1 7 8 9

Better Readable version

awk '{
      c=1
      while(c!="")
      {
         c="" 
         for(i=1;i<NF;i++)
         {
            n=i+1
            if($i>$n)
            {
              c=$i
              $i=$n
              $n=c
            }
         }
      }
    }1
   ' file

If you have ksh, you may try this

#!/usr/bin/env ksh
while read line ; do 
      set -s +A  cols $line 
      echo ${cols[*]}
done < "input_file"

Test

[akshay@localhost tmp]$ cat test.ksh
#!/usr/bin/env ksh

cat <<EOF | while read line ; do set -s +A  cols $line; echo ${cols[*]};done
5 8 7 6 
1 5 6 8
8 9 7 1
EOF

[akshay@localhost tmp]$ ksh test.ksh
5 6 7 8
1 5 6 8
1 7 8 9

Upvotes: 0

amaurea
amaurea

Reputation: 5067

Consider using perl for this:

perl -ape '@F=sort @F;$_="@F\n"' input.txt

Here -a turns on automatic field splitting (like awk does) into the array @F, -p makes it execute the script for each line and print $_ each time, and -e specifies the script directly on the command line.

Not quite 6 characters, I'm afraid, Sean.

This should have been simple in awk, but it doen't quite have the features needed. If there had been an array $@ corresponding to the fields $1, $2, etc., then the solution would have been awk '{asort $@}' input.txt, but sadly no such array exits. The loops required to move the fields into an array and out of it again make it longer than the bash version:

awk '{for(i=1;i<=NF;i++)a[i]=$i;asort(a);for(i=1;i<=NF;i++)printf("%s ",a[i]);printf("\n")}' input.txt

So awk isn't the right tool for the job here. It's also a bit odd that sort itself doesn't have a switch to control its sorting direction.

Upvotes: 0

user4322779
user4322779

Reputation:

Here is a bash script that can do it. It takes a filename argument or reads stdin, was tested on CentOS and assumes IFS=$' \t\n'.

#!/bin/bash

if [ "$1" ] ; then exec < "$1" ; fi

cat - | while read line
do   
  set $line
  echo $(for var in "$@"; do echo $var; done | sort -n) | tr " " "\t" 
done

If you want to put the output in another file run it as:

cat input_file | sorting_script > another_file

or

sorting_script input_file > another file

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74595

Using a few features that are specific to GNU awk:

$ awk 'BEGIN{ PROCINFO["sorted_in"] = "@ind_num_asc" }
      { delete(a); n = 0; for (i=1;i<=NF;++i) a[$i]; 
        for (i in a) printf "%s%s", i, (++n<NF?FS:RS) }' file
5 6 7 8
1 5 6 8
1 7 8 9

Each field is set as a key in the array a. In GNU awk it is possible to specify the order in which the for (i in a) loop traverses the array - here, I've set it to do so in ascending numerical order.

Upvotes: 1

Sean Bright
Sean Bright

Reputation: 120644

This is the best I got - I'm sure it can be done in 6 characters with awk/sed/perl:

while read line
do
  echo $(printf "%d\n" $line | sort -n) | tr ' ' \\t >> another-file.txt
done < my-input-file.txt

Upvotes: 3

Related Questions