使用awk删除bash字符串中的重复项

时间:2017-09-12 21:00:02

标签: bash awk

当我注意到它没有按预期工作时,我试图应用此处提出的方法{Removing duplicates on a variable without sorting}来删除字符串中的重复项。

例如,假设我们有:

s="apple apple tree appleapple tree"

删除重复项我们希望得到以下输出:

apple tree appleaplle

应该通过将以下命令应用于字符串(链接中的完整说明)来获得:

awk 'BEGIN{RS=" "; ORS=" "}{ if(a[$0] == 0){a[$0]+=1; print $0}}' <<< $s

它使用关联数组,因此我们不希望打印两次相同的记录。但是,按照这种方法,我得到了这个

 apple tree appleapple tree

根据需要删除了第一个apple副本,但不是最后一个。 事实上,如果我们打印每条记录的长度,我们会看到最后一条记录不是tree而是tree +返回字符(我想是这样)。

$ awk 'BEGIN{RS=" "; ORS=" "}{ print length($0); print $0}' <<< $s
$ 5 apple 5 apple 4 tree 10 appleapple 5 tree

请注意,最后一棵树确实是5个字符而不是4个字符,导致破坏关联数组方法。

我不明白为什么会有这个角色,它来自哪里? 以及如何解决此问题以使用此方法删除重复项?

非常感谢您的任何建议

4 个答案:

答案 0 :(得分:3)

如上所述,通过将RS设置为" ",这意味着\n不再是记录之间的字符,因此它将成为输入行"tree\n"上最后一个字段的一部分。

FWIW如果您有多字符RS的GNU awk,您可以这样做:

awk -v RS='\\s+' '!seen[$0]++{printf "%s%s", (NR>1?OFS:""), $0} END{print ""}'

答案 1 :(得分:2)

此示例显示您怀疑是正确的:

$ echo "apple apple tree appleapple tree" | awk 'BEGIN{RS=" "; ORS=" "}
{ printf("%s |%s| ", length($0), $0)}'
5 |apple| 5 |apple| 4 |tree| 10 |appleapple| 5 |tree
|

我会使用FS来获取所有不同的值,如下所示:

$ echo "apple apple tree appleapple tree" | awk '{for (i=1; i<=NF; i++) 
printf "%s %s\n", length($i), $i}'
5 apple
5 apple
4 tree
10 appleapple
4 tree

摆脱双打:

echo "apple apple tree appleapple tree" | awk 'BEGIN{ORS=" "}{for (i=1; 
i<=NF; i++)a[$i]++} END {for (i in a) print i }'

答案 2 :(得分:2)

如果您不需要维护单词顺序:

$ ( set -f; printf "%s\n" $s | sort -u | paste -sd" " )
apple appleapple tree

如果您确实想要保留订单:

$ awk '                                                                                                      
    {          
        delete seen
        sep=""
        for (i=1; i<=NF; i++) {
            if (!seen[$i]++) {
                printf "%s%s", sep, $i
            }
            sep=OFS
        }
        print ""
    }
' <<<"$s"
apple tree appleapple

答案 3 :(得分:0)

这是我对重复记录所做的:

awk '{if(arr[$1]!="true") print $1; arr[$1]="true"}' file.txt