如何在linux中删除文件中的特定重复字符串

如何在linux中删除文件中的特定重复字符串,linux,sed,awk,uniq,Linux,Sed,Awk,Uniq,我有一个列表,其中包含与IP地址配对的数据,我只想查看一次IP地址,不想更改顺序 192.168.0.100 fred is happy 192.168.0.100 fred likes pie 192.168.0.100 pie is good 192.168.0.110 tom like cake 192.168.0.110 cake is good 192.168.0.110 pie is better 192.168.0.112 bill lik

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

192.168.0.100 fred is happy 192.168.0.100 fred likes pie 192.168.0.100 pie is good 192.168.0.110 tom like cake 192.168.0.110 cake is good 192.168.0.110 pie is better 192.168.0.112 bill like lettuce 192.168.0.112 lettuce is good for you 192.168.0.112 cake and pie are better tasting than lettuce 我想做的只是删除重复的IP地址,但保持一切完全相同

我想让它看起来像这样

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 我不想碰任何重复的单词,也不能改变顺序


谢谢如果您能提供帮助

我想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

我猜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
使用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
使用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

这可能适用于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

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

这可能适用于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

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

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

$ 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地址中的.s是表示任何字符的RE元字符,因此它们可能适用于某些示例数据,但如果提供其他输入,则可能会得到错误匹配。

无论文件中的间距和/或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地址中的.s是RE元字符,表示任何字符,因此它们可能适用于某些示例数据,但如果提供其他输入,则可能会得到错误匹配。

还有一个:

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

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

谢谢你,我的盒子,我不得不做一个小的调整,但我用你的例子达到了我需要的地方。这可以完全重新排序输入操作符提供的输出-输出将按照数组散列图的遍历顺序进行,这可能不是输入的顺序。@EdMorton我实际上假设Gawk总是按照顺序进行设置,除非删除某些内容,但这是不对的吗?想象一下awk的一个实现,不管怎样,新的密钥总是附加在列表的末尾。是的,这是错误的。有几种方法可以使用PROCINFO[]指定顺序,但默认情况下,您需要假定任何遍历顺序都是正确的。@konsolebox-数组不是存储为列表,而是存储为哈希表,以便快速访问。同样,假设a[x]=3;a[y]=4;a[x]=2-打印数组a时,a[x]应该在[y]之前打印,因为它是在[y]之后创建的,还是在[y]之后创建的,因为[x]在[y]之后填充了它的最终值,还是应该先打印[x],因为它是按字母顺序排在第一位的还是其他什么?关键是,对于任何给定的应用程序,没有明显的顺序比任何其他顺序更可能是正确的,因此,如果重要的话,将其留给用户来管理顺序是有意义的。感谢konsolebox,我不得不做一个小的调整,但我用你的例子达到了我需要的地方。这可以完全重新排序输入操作符提供的输出-输出将按照数组散列图的遍历顺序进行,这可能不是输入的顺序。@EdMorton我实际上假设Gawk总是按照顺序进行设置,除非删除某些内容,但这是不对的吗?想象一下awk的一个实现,不管怎样,新的密钥总是附加在列表的末尾。是的,这是错误的。有几种方法可以使用PROCINFO[]指定顺序,但默认情况下,您需要假定任何遍历顺序都是正确的。@konsolebox-数组不是存储为列表,而是存储为哈希表,以便快速访问。同样,假设a[x]=3;a[y]=4;a[x]=2-打印数组a时,a[x]应该在[y]之前打印,因为它是在[y]之后创建的,还是在[y]之后创建的,因为[x]在[y]之后填充了它的最终值,还是应该先打印[x],因为它是按字母顺序排在第一位的还是其他什么?关键是,对于任何给定的应用程序,没有明显的顺序比任何其他顺序更可能是正确的,因此如果重要的话,让用户来管理顺序是有意义的。我错了,我没有让它工作分隔符是空格。我错了,我没有让它工作分隔符是空格。1很好!我花了一点时间说服自己,最后的1美元,s和1美元中的“.”不会有问题,但我认为不会有问题
由于首字母A[$1]++保证该行的开头与您在sub中使用的$1完全相同,因此.s将对齐。谢谢@EdMorton,确实,ERE点将始终与此处的文字点匹配:-…1很好!我花了一点心思说服自己,最后的sub$1,s与$1中的“.”不会有问题,但我不认为他们会有问题,因为最初的a[$1]++保证该行以与您在sub中使用的完全相同的$1开头,因此.s将对齐。谢谢@EdMorton,确实,此处的ERE点将始终与字面上的点匹配:-。。