使用bash水平排序数据



我有一个充满数据列的文件

sarah mark john
10    20   5
x     y    z 

我想对数据进行排序,使列保持不变,但第二行按递增顺序排列,所以它看起来像这样:

john sarah mark
5    10    20 
z    x     y 

我一直在看排序命令,但只能找到垂直排序,而不是水平排序。我很乐意使用任何工具,任何帮助都很感激。谢谢你!

让我们创建一个函数来转换文件(使行变为列,列变为行):

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)
              }
        }'
}

这只是将所有数据加载到二维数组a[line,column]中,然后将其打印为a[column,line],因此它将给定的输入转置。包装器transpose () { }用于将其存储为bash函数。您只需要将它复制粘贴到您的shell中(或者在~/.bashrc中,如果您希望它成为一个永久函数,在您打开会话的任何时候都可以使用)。

那么,通过使用它,我们可以很容易地通过使用sort -n -k2来解决问题:基于列2进行数字排序。然后,转置。

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

如果你想要一个好的格式作为最终输出,只需像这样管道到column:

$ 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

来自一个重复的问题,这将按第一行对列进行排序:

#!/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)

按第二行排序,将head -1 $input替换为head -2 $input | tail -1。如果排序应该是数字,则输入sort -n -k2而不是sort -k2

好的一行代码可以完成工作:

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

我发现它在这里:http://www.unix.com/unix-for-advanced-and-expert-users/36039-horizontal-sorting-lines-file-sed-implementation.html

最新更新