awk - 打印带有重复单词的行

标签 awk sed grep

我正在尝试打印所有可以包含相同单词两次或更多次的行

例如使用此输入文件:

cat dog cat
dog cat deer
apple peanut banana  apple
car bus train plane
car train car train

输出应该是

cat dog cat
apple peanut banana  apple
car train car train.

我已经尝试过这段代码并且它有效,但我认为一定有更短的方法。

awk '{ a=0;for(i=1;i<=NF;i++){for(j=i+1;j<=NF;j++){if($i==$j)a=1} } if( a==1 ) print $0}'

稍后我想找到所有这些重复的单词并删除所有重复的条目,除了第一次出现。

所以输入:

cat dog cat lion cat 
dog cat deer
apple peanut banana  apple
car bus train plane
car train car train

期望的输出:

cat dog lion 
dog cat deer
apple peanut banana  
car bus train plane
car train

最佳答案

您可以使用这个 GNU sed 命令:

sed -rn '/(\b\w+\b).*\b\1\b/ p' yourfile
  • -r 激活扩展 re 和 n 停用每一行的隐式打印
  • p 命令然后只打印与前面的 re(斜杠内)匹配的行:
    • \b\w+\b 是单词:单词边界 (\b`) 之间的非空单词字符序列 (\w),这些是 GNU 扩展
    • 由于使用了括号,这样的单词被“存储”在 \1 中供以后重用
    • 然后我们尝试将这个词与 \b\1\b 再次匹配,并在这两个地方之间使用一些可选的 (.*)。
    • 这就是整个技巧:匹配一些东西,将其放在括号中,这样您就可以在与 \1
    • 相同的 re 中重用它

要回答问题的第二部分,删除第一部分之后的双字,但打印所有行(仅修改带有双字的行),您可以使用一些 sed s 魔法:

sed -r ':A s/(.*)(\b\w+\b)(.*)\b\2\b(.*)/\1\2\3\4/g; t A ;'
  • 这里我们再次使用反向引用技巧。
  • 但是我们必须考虑双字之前、之间和之后的内容,因此我们在 then s 命令的匹配部分有一个 \2 并且我们在替换部分中有其他反向引用。
  • 请注意,只有 \2 在匹配部分没有括号,我们在替换中使用了所有组,因此我们有效地删除了对中的第二个单词。
  • 为了更多的单词重复,我们需要循环:
    • :A是一个标签
    • t A 如果在最后一个 s comamnd 中完成了替换,则跳转到标签
    • 这在 s 周围构建了一个“while 循环”以删除其他重复项

关于awk - 打印带有重复单词的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41748294/

相关文章:

regex - 仅打印带有大写字母的单词 (Linux)

bash - 在 awk printf 中使用可变长度的提示

regex - 编码正则表达式以返回 true 以获取组的精确计数

command-line - 可以设置 grep(来自命令行)以突出显示匹配的行部分吗?

linux - 在小数点前插入逗号恰好 1 个空格

regex - 使用 sed 仅替换字符的单个实例

Bash sed 非贪婪匹配

bash - 交换不同长度字符串中特定位置的字符

linux - 找到 PATTERN 时合并两个文本文件的行

shell - grep 查找包含特定单词的行