给定一个这样的排序文件:
AAA 1 2 3
AAA 2 3 4
AAA 3 4 2
BBB 1 1 1
BBB 1 2 1
和所需的输出
AAA 1 2 3
BBB 1 1 1
用 sed 实现这一目标的最佳方法是什么?
基本上,如果 col 以与上一行相同的字段开头,我该如何删除它?其余数据必须保留在输出中。
我想必须有某种方法可以使用保持缓冲区、分支或测试命令来做到这一点。
这可以通过 AWK 完成:
$ gawk '{if (last != $1) print; last = $1}' in.txt
AAA 1 2 3
BBB 1 1 1
awk 的另一种方式:
awk '!($1 in a){print;a[$1]}' file
也许有一个更简单的方法sed
,但是:
sed ':a;N;/\([[:alnum:]]*[[:space:]]\).*\n\1/{s/\n.*//;ta};P;D'
这会产生输出
AAA 1 2 3
BBB 1 1 1
这与问题中的不同,但与描述相匹配:
如果 col 以与上一行相同的字段开头,我该如何删除它?
这可能对您有用(GNU sed):
sed -r ':a;$!N;s/^((\S+\s).*)\n\2.*/\1/;ta;P;D' file
或者也许只是:
sort -uk1,1 file
一种使用方式GNU awk
:
awk '!array[$1]++' file.txt
结果:
AAA 1 2 3
BBB 1 1 1
使用 sed:
#!/bin/sed -nf
P
: loop
s/\s.*//
N
/\([^\n][^\n]*\)\n\1/ b loop
D
首先,我们必须将-n
标志传递给 sed,以便它只打印我们告诉它的内容。
我们首先使用“P”命令打印该行,因为第一行将始终被打印,并且我们将强制 sed 仅在需要时执行该行。
现在我们将做一个循环。我们通过“:”命令定义一个带有起始标签的循环(在这种情况下,我们将标签命名为“loop”),必要时我们使用“b”命令(或“t”测试命令)。这个循环非常简单:
\(
和结尾\)
)。在这种情况下,我们匹配所有不是换行符(即[^\n]
)的字符,直到行尾。我们通过匹配至少一个非换行符和它们的任意序列来做到这一点。这可以防止在换行符之前匹配空字符串。捕获后,我们使用特殊变量匹配换行符和捕获结果\1
,其中包含与第一次捕获匹配的输入。如果成功,我们有一行重复第一个字段,所以我们用“b”分支命令跳回到循环的开头。这可以缩短为一行(注意我们已将“循环”标签重命名为“a”):
sed -e 'P;:a;s/\s.*//;N;/\([^\n][^\n]*\)\n\1/ba;D'