Using bash to sort data horizontally

后端 未结 3 2097
执念已碎
执念已碎 2020-11-27 22:21

I have a file full of data in columns

sarah mark john
10    20   5
x     y    z 

I want to sort the data so the columns stay intact but the

相关标签:
3条回答
  • 2020-11-27 23:02

    Good one-liner gets the job done:

    perl -ane '$,=" "; print sort @F; print "\n";' file

    I found it here: http://www.unix.com/unix-for-advanced-and-expert-users/36039-horizontal-sorting-lines-file-sed-implementation.html

    0 讨论(0)
  • 2020-11-27 23:04

    Let's create a function to transpose a file (make rows become columns, and columns become rows):

    transpose () {
      awk '{for (i=1; i<=NF; i++) a[i,NR]=$i; max=(max<NF?NF:max)}
            END {for (i=1; i<=max; i++)
                  {for (j=1; j<=NR; j++) 
                      printf "%s%s", a[i,j], (j<NR?OFS:ORS)
                  }
            }'
    }
    

    This just loads all the data into a bidimensional array a[line,column] and then prints it back as a[column,line], so that it transposes the given input. The wrapper transpose () { } is used to store it as a bash function. You just need to copy paste it in your shell (or in ~/.bashrc if you want it to be a permanent function, available any time you open a session).

    Then, by using it, we can easily solve the problem by using sort -n -k2: sort numerically based on column 2. Then, transpose back.

    $ cat a | transpose | sort -n -k2 | transpose
    john sarah mark
    5 10 20
    z x y
    

    In case you want to have a nice format as final output, just pipe to column like this:

    $ cat a | transpose | sort -n -k2 | transpose | column -t
    john  sarah  mark
    5     10     20
    z     x      y
    

    Step by step:

    $ cat a | transpose 
    sarah 10 x
    mark 20 y
    john 5 z
    $ cat a | transpose | sort -n -k2
    john 5 z
    sarah 10 x
    mark 20 y
    $ cat a | transpose | sort -n -k2 | transpose 
    john sarah mark
    5 10 20
    z x y
    
    0 讨论(0)
  • 2020-11-27 23:26

    Coming from a duplicate question, this would sort the columns by the first row:

    #!/bin/bash
    
    input="$1"
    
    order=$((for i in $(head -1 $input); do echo $i; done) | nl | sort -k2 | cut -f1)
    
    grep ^ $input | (while read line
      do
        read -a columns <<< "${line%"${line##*[![:space:]]}"}"
    
        orderedline=()
        for i in ${order[@]}
        do
          orderedline+=("${columns[$i - 1]}")
        done
        line=$(printf "\t%s" "${orderedline[@]}")
        echo ${line:1}
      done)
    

    To sort by second row, replace head -1 $input with head -2 $input | tail -1. If the sort should be numeric, put in sort -n -k2 instead of sort -k2.

    0 讨论(0)
提交回复
热议问题