我们有以下文本文件:
172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.32.163 172.55.33.95
我们需要做的是,如果发现第一列包含之前在该列中遇到的值,则交换这两列。对于每个这样的值(在本例中为 IP 地址),最大出现次数为两次。
在上面的例子中,我们需要 172.55.33.95
与上一行已经找到的172.55.32.163
内容进行交换。172.55.32.163
我试过
awk 'prev && ($1 != prev) {print seen[prev]} {seen[$1] = $0; prev = $1} END {print seen[$1]}' /tmp/new.txt
但这有助于删除之前已经找到第 1 列条目的行。
答案可能就像这个 awk 程序一样简单:
这将通过增加相应的数组值来将每个列 1 值的出现次数存储在数组中
found
。如果发现该值大于一,则意味着当前值已经遇到过,列需要交换。为此,将列 1 的值存储在缓冲区中,用列 2 的值替换,再用缓冲的值替换列 2 的值。最后,将打印当前行,包括所有修改(如果有),这就是看似“杂散”的含义
1
。这种简单的方法有一个缺点:如果新的第 1 列(以前是第 2 列)值在后面的一行中再次出现在第 1 列中,或者在前一行中已经出现,则不会捕获此错误。改进的版本考虑了后面行中出现的错误,并省略了交换也会产生重复的第 1 列条目的行,如下所示:
在 Perl 中你可以这样做:
-l
\n
:在传递给的脚本的每次评估之前和之后自动删除并自动添加默认记录字段分隔符( )-e
;-a
脚本会将输出字段分隔符设置为
,然后对于每一行,它将检查第一个字段是否已存储在 中
@buf
。如果是,就将当前记录反转并打印;否则,就打印当前记录,并将第一个字段添加到
@buf
。您的要求不明确,并且您的示例没有涵盖您可能想要表达的所有可能性,但是,使用任何 awk,这都可以实现您可能想要表达的一件事:
或者你可能想要:
或者:
或者: