簡體   English   中英

按bash中的行數對文本列進行排序

[英]Sort text columns by number of lines in bash

假設一個包含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中實現它聽起來比實際更容易。)

使用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

首先創建一個名為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以將列轉置為行以獲得原始順序

PS:由於使用FPAT我們需要gnu-awk。

使用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     -
sed -e 's/^ *//' columns.txt
# =>
# foo  foo  foo
# bar  bar  bar
# baz  baz
# qux

我整個星期都會在這里! :d

更嚴重的是,您可能希望使用bash轉置列 ,使用awkrs 這樣可以更輕松地對列(現在是行)進行排序,並再次將它們轉置回來。 但是,多個空格可能會給awk帶來awk

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM