使用Shell脚本从字符串中删除所有重复的单词


12

我有一个像

"aaa,aaa,aaa,bbb,bbb,ccc,bbb,ccc"

我想从字符串中删除重复的单词,然后输出将像

"aaa,bbb,ccc"

我尝试过此代码

$ echo "zebra ant spider spider ant zebra ant" | xargs -n1 | sort -u | xargs

使用相同的值可以正常工作,但是当我提供变量值时,它也会显示所有重复的单词。

如何删除重复的值。

更新

我的问题是如果用户相同,则将所有对应的值添加到单个字符串中。我有这样的数据->

   user name    | colour
    AAA         | red
    AAA         | black
    BBB         | red
    BBB         | blue
    AAA         | blue
    AAA         | red
    CCC         | red
    CCC         | red
    AAA         | green
    AAA         | red
    AAA         | black
    BBB         | red
    BBB         | blue
    AAA         | blue
    AAA         | red
    CCC         | red
    CCC         | red
    AAA         | green

在编码中,我获取了所有不同的用户,然后成功连接了颜色字符串。为此,我正在使用代码-

while read the records 

    if [ "$c" == "" ]; then  #$c I defined global
        c="$colour1"
    else
        c="$c,$colour1" 
    fi

当我打印此$ c变量时,我得到输出(对于用户AAA)

"red,black,blue,red,green,red,black,blue,red,green,"

我想删除重复的颜色。然后所需的输出应该像

"red,black,blue,green"

对于此所需的输出,我使用了上面的代码

 echo "zebra ant spider spider ant zebra ant" | xargs -n1 | sort -u | xargs

但是它将显示具有重复值的输出。

“红色,黑色,蓝色,红色,绿色,红色,黑色,蓝色,红色,绿色,”谢谢


3
请说明您使用的是什么问题。我不明白“当我给我可变价值时”的意思。你给什么价值?它在哪里失败?
terdon

echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsaaa bbb ccc..,因此您需要显示累了的确切代码,并输出您得到的..,该字符串带有变量:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

字符串值是动态产生的。它正在打印相同的值(包含重复值)。
Urvashi

1
是的,显示失败的代码,否则我们怎么知道可能出了什么问题?
Sundeep

顺序重要吗?
Jacob Vlijm '17

Answers:


12

一个又一个,只是为了好玩:

$ a="aaa bbb aaa bbb ccc aaa ddd bbb ccc"
$ echo "$a" | awk '{for (i=1;i<=NF;i++) if (!a[$i]++) printf("%s%s",$i,FS)}{printf("\n")}'
aaa bbb ccc ddd 

顺便说一句,即使您的解决方案也可以很好地使用变量:

$ b="zebra ant spider spider ant zebra ant" 
$ echo "$b" | xargs -n1 | sort -u | xargs
ant spider zebra

整洁的方法。我唯一要做的调整是使用%s而不是%s%s。原因是我在结果中进行了一个for循环,而两个空格给正则表达式匹配带来了一些挑战。
JeremyCanfield '19

9

随着trsortuniq

echo "zebra ant spider spider ant zebra ant" | tr ' ' '\n' | sort | uniq

要么

echo "zebra ant spider spider ant zebra ant" | tr ' ' '\n' | sort | uniq | xargs 

得到一条线


您需要添加 | xargs重新加入输出到一条线
腓力

4
或使用sort -u。甚至一个awk '!u[$0]++
贝诺19年

2
@Benoît哇,我不知道sort -u。我一直都在用sort | uniq。浪费了的按键...
gardenhead

8
$ echo "zebra ant spider spider ant zebra ant"  | awk -v RS="[ \n]+" '!n[$0]++' 
zebra
ant
spider

1
非常聪明!!!!
George Vasiliou

@GeorgeVasiliou,谢谢[或说实话,非常懒惰:-)]
JJoao

2

与gnu sed

sed ':s;s/\(\<\S*\>\)\(.*\)\<\1\>/\1\2/g;ts'

您可以添加;s/ */ /g以删除重复的空格。

像这样的功能:如果该行中第二次出现一个单词,请将其删除并重新开始,直到不再发现任何复制。


什么是\<\>
someonewithpc

@someonewithpc它们不匹配任何字符,但匹配单词的开头和结尾以防止子字符串匹配。
Philippos

不错,但是可移植吗?另外,单词不是用空格分隔吗?似乎多余以匹配不带空格的单词后跟单词。
someonewithpc

1
@someonewithpc不,这不是标准的,这就是为什么我写了gnu sed的原因。令人高兴的是,您不必分别处理第一个和最后一个字符串
Philippos

2
perl -lane '$,=$";print grep { ! $h{$_}++ } @F'

2

awk的强制性解决方案:

$ echo "ant zebra ant spider spider ant zebra ant" | 
   awk -vRS=" " -vORS=" " '!a[$1] {a[$1]++} END{ for (x in a) print x;  } ' ; echo
zebra ant spider 

echo换行符有最后的提示)


加一个awk!我也只是出于娱乐目的而构建了awk解决方案。由于awk会在阵列键中随机出现,因此在END部分以随机顺序打印单词的可能性很小。
乔治·瓦西里乌

是的,它们将以基本上随机的顺序打印。但是,该sort解决方案也不保留原始顺序。
ilkkachu

是的,很好!甚至以与输入不同的顺序对打印进行排序。
乔治·瓦西里乌

1
@ilkkachu实际上,我们不需要等待输入结束。我们可以对您的代码进行稍微的修改,决定是否打印:awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echo这将保留订单。

1

蟒蛇

选项1

#!/usr/bin/env python
# get_unique_words.py

import sys

l = []
for w in sys.argv[1].split(','):
  if w not in l:
    l += [ w ]
print ','.join(l)

使可执行文件,然后从Bash调用:

$ ./get_unique_words.py "aaa,aaa,aaa,bbb,bbb,ccc,bbb,ccc"
aaa,bbb,ccc

或者您可以将其实现为Bash函数,但是语法混乱。

get_unique_words(){
  python -c "
l = []
for w in '$1'.split(','):
  if w not in l:
    l += [ w ]
print ','.join(l)"
}

选项2

如果需要,此选项可以变成单线:

#!/usr/bin/env python
# get_unique_words.py

import sys

s_in = sys.argv[1]
l_in = s_in.split(',') # Turn string into a list.
set_out = set(l_in) # Turning a list into a set removes duplicates items.
s_out = ','.join(set_out) 
print s_out

在Bash中:

get_unique_words(){
  python -c "print ','.join(set('$1'.split(',')))"
}

0
cat filename | awk '{ delete a; for (i=1; i<=NF; i++) a[$i]++; n=asorti(a, b); for (i=1; i<=n; i++) printf b[i]" "; print "" }' > newfile

我不明白
Pierre.Vriens

1
您的代码缺少解释。没有解释,很难跟踪正在发生的事情。您似乎还对似乎错误的数据(用空格分隔的字段)和awk所使用的特定实现(asorti()不是标准awk功能)进行了假设。
库沙兰丹

0

在名为的文件中使用原始表格数据file

sed '1d' file | sort -u |
awk '{ color[$1] = ( color[$1] == "" ? $3 : color[$1] "," $3 ) }
     END { for (user in color) print user, color[user] }'

这产生

CCC red
BBB blue,red
AAA black,blue,green,red

管道的三个步骤:

  1. sed命令将删除第一行,该行是我们不想读取的标题。
  2. sort命令为我们提供了独特的线条。样例数据sort如下

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
  3. awk命令获取此数据,并为数组中的每个用户生成一个逗号分隔的字符串color(其中用户名是数组的键)。最后(在该END块中)输出所有收集的数据。

-2
a="aaa aaa aaa bbb bbb ccc bbb ccc"
for item in $a
do
   echo $item
done | sort -u | (while read i; do ans="$ans $i"; done ; echo $ans)

请添加有关您的代码如何工作以及为什么这样做的解释。
xhienne
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.