工具sed 并不是真正为这项工作而设计的。 sed 只有两种形式的记忆,模式空间和保持空间,它们只不过是它可以记住的两个简单的字符串。每次对这样的内存块进行操作时,都必须重写整个内存块并重新分析它。另一方面,Awk 在这里有更多的灵活性,并且可以更容易地操作有问题的行。
awk '{delete s}
{for(i=1;i<=NF;++i) if(!(s[$i]++)) printf (i==1?"":OFS)"%s",$i}
{printf ORS}' file
但是由于您在 Windows 机器上工作,这也意味着您有 CRLF 行尾。这可能会对最后一个条目产生轻微的问题。如果该行显示:
foo bar foo
awk 会读作
foo bar foo\r
因此,由于 CR,最后一个 foo 将与第一个 foo 不匹配。
现在改正为:
awk 'BEGIN{RS=ORS="\r\n"}
{delete s}
{for(i=1;i<=NF;++i) if(!(s[$i]++)) printf (i==1?"":OFS)"%s",$i}
{printf ORS}' file
这可以使用,因为您使用的是最终 GNU 的 CygWin,因此我们可以使用 RS 的扩展名作为正则表达式或多字符值。
如果您希望区分大小写,可以将s[$i] 替换为s[tolower($i)]。
像这样的句子仍然存在问题
"There was a horse in the bar, it ran out of the bar."
单词bar 可以在这里匹配,但, 和. 使它不匹配。这可以通过以下方式解决:
awk 'BEGIN{RS=ORS="\r\n"; ere="[,.?:;\042\047]"}
{delete s}
{for(i=1;i<=NF;++i) {
key=tolower($i); sub("^" ere,"",key); sub(ere "$","",key)
if(!(s[key]++)) printf (i==1?"":OFS)"%s",$i
}
}
{printf ORS}' file
这本质上是相同的,但删除了单词开头和结尾的标点符号。标点符号列在ere