【问题标题】:How can you remove specific duplicate strings in a file in linux如何在 linux 中删除文件中的特定重复字符串
【发布时间】:2013-09-13 19:52:18
【问题描述】:

我有一个包含与 IP 地址配对的数据的列表,我只想查看一次 IP 地址并且不想更改顺序。

192.168.0.100 弗雷德很开心 192.168.0.100 弗雷德喜欢馅饼 192.168.0.100 馅饼不错 192.168.0.110 像蛋糕一样的汤姆 192.168.0.110 蛋糕不错 192.168.0.110 馅饼更好 192.168.0.112 像生菜一样的钞票 192.168.0.112 生菜对你有好处 192.168.0.112 蛋糕和派比生菜好吃

我想要做的只是删除重复的 IP 地址,但保持一切完全相同。

我想让它看起来像这样

192.168.0.100 弗雷德很开心 弗雷德喜欢馅饼 馅饼很好 192.168.0.110 像蛋糕一样的汤姆 蛋糕很好 馅饼更好 192.168.0.112 像生菜一样的钞票 生菜对你有好处 蛋糕和派比生菜好吃

我不想碰任何重复的单词,我无法更改顺序

如果你能帮忙,谢谢

【问题讨论】:

    标签: linux sed awk uniq


    【解决方案1】:

    无论文件中包含何种间距和/或 RE 元字符,这都将起作用:

    $ awk '
    { key = $1 }
    key == prev { sub(/[^[:space:]]+/,sprintf("%*s",length(key),"")) }
    { prev = key; print }
    ' file
    192.168.0.100    fred is happy
                     fred likes pie
                     pie is good
    192.168.0.110    tom like cake
                     cake is good
                     pie is better
    192.168.0.112    bill like lettuce
                     lettuce is good for you
                     cake and pie are better tasting than lettuce
    

    注意在 RE 上下文中使用 $1 的解决方案,因为 IP 地址中的“.”是 RE 元字符,表示“任何字符”,因此它们可能适用于某些示例数据,但在给定其他输入的情况下您可能会得到错误的匹配。

    【讨论】:

      【解决方案2】:

      我猜ip和文本之间的分隔符是tab,那么这个单行应该适合你:

      awk -F'\t' -v OFS='\t' 'a[$1]{gsub(/./," ",$1);print;next}{a[$1]=1}7' file
      

      用你的文件测试:

      kent$  awk -F'\t' -v OFS='\t' 'a[$1]{gsub(/./," ",$1);print;next}{a[$1]=1}7' f
      192.168.0.100   fred is happy
                      fred likes pie
                      pie is good
      192.168.0.110   tom like cake
                      cake is good
                      pie is better
      192.168.0.112   bill like lettuce
                      lettuce is good for you
                      cake and pie are better tasting than lettuce
      

      【讨论】:

      • 我错了,我没有让它工作,分隔符是空格。
      【解决方案3】:

      使用 awk:

      awk 'BEGIN{FS=OFS="    "}{t=$1;if(t in a){gsub(/./," ",$1);a[t]=a[t]RS$0}else{a[t]=$0}}END{for(i in a)print a[i]}' file
      

      输出:

      192.168.0.100    fred is happy
                       fred likes pie
                       pie is good
      192.168.0.110    tom like cake
                       cake is good
                       pie is better
      192.168.0.112    bill like lettuce
                       lettuce is good for you
                       cake and pie are better tasting than lettuce
      

      【讨论】:

      • 感谢 konsolebox,我不得不做一个小的调整,但我已经通过你的例子到达了我需要的地方。
      • 这可以完全重新排序由 in 运算符提供的输出 - 输出将按照数组哈希映射的遍历顺序,而这可能不是输入的顺序。
      • @EdMorton 我实际上假设 Gawk 始终按顺序设置它,除非删除某些内容,但这是不正确的吗?想象一下 awk 的实现,无论如何,新键总是会附加在列表的末尾。
      • 是的,这是不正确的。您可以通过多种方式使用 PROCINFO[] 指定排序,但默认情况下,您需要假设任何遍历顺序都可以。
      • @konsolebox - 数组不存储为列表,它们存储为哈希表以便快速访问。另外,想象a[x]=3; a[y]=4; a[x]=2 - 打印数组时a 应该在a[y] 之前打印a[x],因为它是先创建的或在a[y] 之后创建的,因为a[x]a[y] 之后填充了它的最终值,或者应该a[x] 先打印是因为它按字母顺序排在第一位还是其他?关键是对于任何给定的应用程序,没有任何明显的顺序比任何其他顺序更可能是正确的,因此如果重要的话,让用户来管理顺序是有意义的。
      【解决方案4】:

      还有一个:

      awk 'A[$1]++{s=$1; gsub(/./,FS,s); sub($1,s)}1' file
      

      【讨论】:

      • 1 不错!想了想说服自己最后的 sub($1,s) 不会有问题 $1 中的 '.' 但我不认为他们会因为最初的 A[$1]++ 保证线路开始与您在 sub() 中使用的 $1 完全相同,因此 .s 将对齐。
      • 感谢@EdMorton,确实 ERE 点将始终与此处的文字点匹配 :-) ..
      【解决方案5】:

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

      sed -r '1{:a;p;h;s/\s.*//;s/./ /g;H;d};G;s/^(\S+)(\s.*)\n\1.*\n(.*)/\3\2/;t;s/\n.*//;ba' file
      

      打印第一条记录和键发生变化的记录,并将键及其补码存储在保持空间的空格中。对于后续记录,将存储的密钥与当前密钥进行比较,对于匹配的记录,将当前密钥替换为空格的补充。对于那些不匹配的键,删除存储的键并补充并从头开始重复。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-21
        • 1970-01-01
        • 1970-01-01
        • 2021-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多