假设一个文本文件包含 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 中实现它听起来比实际上更容易。)
答案 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
步骤是:
transpose
函数将列转置为行awk
在每行的开头添加字段数sort
cut
删除第一列transpose
以将列转置为行以获得原始订单 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 bash,awk
或rs
。这样可以更轻松地对列(现在是行)进行排序,并再次将它们转置回来。
但是,多个空格可能会给awk
带来问题。