0

给定一个这样的排序文件:

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 以与上一行相同的字段开头,我该如何删除它?其余数据必须保留在输出中。

我想必须有某种方法可以使用保持缓冲区、分支或测试命令来做到这一点。

4

6 回答 6

1

这可以通过 AWK 完成:

$ gawk '{if (last != $1) print; last = $1}' in.txt
AAA 1 2 3
BBB 1 1 1
于 2012-10-01T18:53:39.750 回答
1

awk 的另一种方式:

awk '!($1 in a){print;a[$1]}' file
于 2012-10-01T18:59:30.453 回答
0

也许有一个更简单的方法sed,但是:

sed ':a;N;/\([[:alnum:]]*[[:space:]]\).*\n\1/{s/\n.*//;ta};P;D'

这会产生输出

AAA 1 2 3
BBB 1 1 1

这与问题中的不同,但与描述相匹配:

如果 col 以与上一行相同的字段开头,我该如何删除它?

于 2012-10-01T19:00:17.517 回答
0

这可能对您有用(GNU sed):

sed -r ':a;$!N;s/^((\S+\s).*)\n\2.*/\1/;ta;P;D' file

或者也许只是:

sort -uk1,1 file
于 2012-10-01T20:22:55.623 回答
0

一种使用方式GNU awk

awk '!array[$1]++' file.txt

结果:

AAA 1 2 3
BBB 1 1 1
于 2012-10-02T04:21:38.847 回答
0

使用 sed:

#!/bin/sed -nf

P

: loop
s/\s.*//
N
/\([^\n][^\n]*\)\n\1/ b loop

D

首先,我们必须将-n标志传递给 sed,以便它只打印我们告诉它的内容。

我们首先使用“P”命令打印该行,因为第一行将始终被打印,并且我们将强制 sed 仅在需要时执行该行。

现在我们将做一个循环。我们通过“:”命令定义一个带有起始标签的循环(在这种情况下,我们将标签命名为“loop”),必要时我们使用“b”命令(或“t”测试命令)。这个循环非常简单:

  1. 删除除第一个字段以外的所有内容(将第一个空格字符及其后面的所有内容替换为空)
  2. 追加下一行(将包含换行符)
  3. 检查新行是否以我们隔离的字段开头。我们通过使用捕获来做到这一点。捕获被定义为“子匹配”,其匹配的输入将存储到一个特殊的“变量”中,按照捕获的顺序以数字方式命名。我们使用带反斜杠转义的括号指定捕获(以 开头\(和结尾\))。在这种情况下,我们匹配所有不是换行符(即[^\n])的字符,直到行尾。我们通过匹配至少一个非换行符和它们的任意序列来做到这一点。这可以防止在换行符之前匹配空字符串。捕获后,我们使用特殊变量匹配换行符和捕获结果\1,其中包含与第一次捕获匹配的输入。如果成功,我们有一行重复第一个字段,所以我们用“b”分支命令跳回到循环的开头。
  4. 当我们退出循环时,我们发现一行具有不同的第一个字段,因此我们必须准备输入行并跳回脚本的开头。这可以通过“D” delete-first-line-and-restart-script 命令来完成。

这可以缩短为一行(注意我们已将“循环”标签重命名为“a”):

sed -e 'P;:a;s/\s.*//;N;/\([^\n][^\n]*\)\n\1/ba;D'
于 2012-10-02T13:11:43.910 回答