按bash中的行数对文本列进行排序

时间:2016-11-28 18:36:38

标签: string bash sorting awk multiple-columns

假设一个文本文件包含 x 个字符串列数。

$cat file # where x=3
foo  foo  foo
bar  bar  bar
     baz  baz
     qux

bash 中是否有办法按照它们包含的数字文本字符串(即填充的行)对这些列进行排序,同时保持每列中行的内部顺序?

$sought_command file
foo  foo  foo
bar  bar  bar
baz  baz
qux

基本上,行数最多的列是第一行,第二行数最多的行是第二行,等等。

(此任务很容易通过R实现,但我想通过 bash 解决问题。)

编辑1

以下是一些其他细节:每列包含至少一个文本字符串(即一个填充的行)。文本字符串可以构成任何字母数字组合并且具有任何长度(但显然不包含空格)。输出列不得插入空行。列分隔符没有先验限制,只要它在整个表中保持一致。

此任务所需的只是按原样移动列,使其按列长度排序。 (我知道在 bash 中实现它听起来比实际上更容易。)

4 个答案:

答案 0 :(得分:4)

使用GNU awk for sorted_in并假设您的列以制表符分隔:

$ cat tst.awk
BEGIN{ FS=OFS="\t" }
{
    for (i=1; i<=NF; i++) {
        if ($i ~ /[^[:space:]]/) {
            cell[NR,i] = $i
            cnt[i]++
        }
    }
    next
}
END {
    PROCINFO["sorted_in"] = "@val_num_desc"
    for (row=1; row<=NR; row++) {
        c=0
        for (col in cnt) {
            printf "%s%s", (c++?OFS:""), cell[row,col]
        }
        print ""
    }
}

$ awk -f tst.awk file
foo     foo     foo
bar     bar     bar
baz     baz
qux

答案 1 :(得分:1)

首先创建一个名为transpose的函数:

transpose() {
   awk -v FPAT='[^[:blank:]]+|[ \t]{3,}' '{
     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?ORS:OFS)
   }'
}

然后将其用作:

transpose < file | awk '{print NF "\t" $0}' | sort -k1nr | cut -f2- | transpose

foo foo foo
bar bar bar
baz baz
qux

步骤是:

  1. 调用transpose函数将列转置为行
  2. 使用awk在每行的开头添加字段数
  3. 以第一列的反向数字顺序使用sort
  4. 使用cut删除第一列
  5. 再次致电transpose以将列转置为行以获得原始订单
  6. PS:由于使用FPAT,我们需要gnu-awk。

答案 2 :(得分:1)

使用unix工具集

$ tr '\t' '\n' <file                  | 
  pr -4ts                             |  
  awk '{print gsub(/-/,"-") "\t" $0}' | 
  sort -k1n                           | 
  cut -f2-                            | 
  tr '\t' '\n'                        | 
  pr -3ts

foo     foo     foo
bar     bar     bar
baz     baz     -
qux     -       -

假设列以制表符分隔,缺失值以“ - ”表示。幻数4和3分别是行数和列数。

将此用作输入文件

$ cat file
foo     foo     foo
bar     bar     bar
-       baz     baz
-       qux     -

答案 3 :(得分:0)

sed -e 's/^ *//' columns.txt
# =>
# foo  foo  foo
# bar  bar  bar
# baz  baz
# qux

我整个星期都在这里! :d

更严重的是,您可能需要transpose your columns with bashawkrs。这样可以更轻松地对列(现在是行)进行排序,并再次将它们转置回来。 但是,多个空格可能会给awk带来问题。