使用AWK重新排序列

6

我需要重新排序这个(以制表符分隔的)数据的列:

   1 cat    plays
   1 dog    eats
   1 horse  runs
   1 red    dog
   1 the    cat
   1 the    cat

所以它的打印输出应该是:
cat plays   1
dog eats    1
horse   runs    1
red dog 1
the cat 2

我尝试过:

sort [input] | uniq -c | awk '{print $2 "\t" $3 "\t" $1}' > [output]

结果如下:

1   cat 1
1   dog 1
1   horse   1
1   red 1
2   the 1

有人能给我一些关于发生了什么问题的见解吗? 谢谢。


1
其他人已经回答了你的问题。作为一种风格,我会写成 awk -v OFS='\t' '{print $3, $4, $1}' - glenn jackman
4个回答

8

由于 cat input | sort | uniq -c 的输出为:

   1    1 cat    plays
   1    1 dog    eats
   1    1 horse  runs
   1    1 red    dog
   2    1 the    cat

你需要类似这样的东西:
cat input | sort | uniq -c | awk '{print $3 "\t" $4 "\t" $1}'

我们可以在awk中指定输出字段分隔符:

cat input | sort | uniq -c | awk -v OFS="\t" '{print $3,$4,$1}'

请注意,如果您在值中有空格,则 awk 会将其拆分。为了避免这种情况,并将分隔符限制为仅制表符,请传递此额外参数:awk -F $'\t' ... - Mathieu Rey

3
< p > < code > uniq -c 命令添加了一列。这应该给你想要的输出:< /p >
$ sort file | uniq -c | awk '{print $3 "\t" $4 "\t" $1}'
cat     plays   1
dog     eats    1
horse   runs    1
red     dog     1
the     cat     2

2

使用 awksort

$ awk '{a[$2 OFS $3]++}END{for(k in a)print k,a[k]}' OFS='\t' file | sort -nk3 
cat     plays   1
dog     eats    1
horse   runs    1
red     dog     1
the     cat     2

2
如果您拥有GNU Awk (gawk),您可以仅使用它及其特性函数asorti():
#!/usr/bin/env gawk -f
{
    a[$2 "\t" $3]++
}
END {
    asorti(a, b)
    for (i = 1; i in b; ++i) print b[i] "\t" a[b[i]]
}

一行代码:

gawk '{++a[$2"\t"$3]}END{asorti(a,b);for(i=1;i in b;++i)print b[i]"\t"a[b[i]]}' file

输出:

cat plays   1
dog eats    1
horse   runs    1
red dog 1
the cat 2

更新:为了保留原始顺序而不进行排序,请使用以下方法:

#!/usr/bin/awk -f
!a[$2 "\t" $3]++ {
    b[++i] = $2 "\t" $3
}
END {
    for (j = 1; j <= i; ++j) print b[j] "\t" a[b[j]]
}

或者

awk '!a[$2"\t"$3]++{b[++i]=$2"\t"$3}END{for(j=1;j<=i;++j)print b[j]"\t"a[b[j]]}' file

任何版本的awk都兼容这个操作。
由于输入已经默认排序,因此输出应该与上次相同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接