Удалить все повторяющиеся слова из строки, используя скрипт

12

У меня есть строка как

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

Я хочу удалить повторяющееся слово из строки, тогда вывод будет

"aaa,bbb,ccc"

Я попробовал этот код Source

$ 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

но он отображает вывод с повторяющимися значениями. Как

"красный, черный, синий, красный, зеленый, красный, черный, синий, красный, зеленый" Спасибо

Urvashi
источник
3
Пожалуйста, уточните, что не так с тем, что вы используете. Я не понимаю, что вы подразумеваете под «когда я даю значение моей переменной». Какую ценность вы даете? Где это терпит неудачу?
Тердон
echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsдает aaa bbb ccc.. так что вам нужно показать точный код, который вы устали и вывод, который вы получили .. со строкой в ​​переменной:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep
Строковое значение приходит динамически. Он печатает то же значение (содержит дублирующее значение).
Урваши
1
да, покажи код, который не удался, иначе как бы мы узнали, что могло пойти не так?
Sundeep
Имеет ли значение заказ?
Джейкоб Влейм

Ответы:

12

Еще один awk, просто для удовольствия:

$ 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 для результатов, и два пробела вызвали некоторые проблемы с совпадениями регулярных выражений.
Джереми Кэнфилд
9

С tr, sortиuniq

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чтобы снова объединить вывод в одну строку
Philippos
4
Или используйте sort -u. Или даже awk '!u[$0]++.
Бенуа
2
@ Бенуа Ого я не знал sort -u. Я использовал sort | uniqвсе это время.
Потраченные
8
$ echo "zebra ant spider spider ant zebra ant"  | awk -v RS="[ \n]+" '!n[$0]++' 
zebra
ant
spider
JJoao
источник
1
Очень умный!!!!
Георгий Василиу
@ GeorgeVasiliou, спасибо [или, честно говоря, очень ленивый :-)]
JJoao
2

С гну sed:

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

Вы можете добавить, ;s/ */ /gчтобы удалить дублирующие пробелы.

Функции, подобные этой: Если слово находится во второй раз в этой строке, удалите его и начинайте сначала, пока повторное копирование не будет найдено.

Philippos
источник
Какие есть \<и \>?
Someonewithpc
@someonewithpc Они не соответствуют ни одному символу, кроме начала и конца слова, чтобы предотвратить совпадение подстрок.
Филиппос
Хорошо, но это портативный? Кроме того, слова не разделены пробелом? Кажется излишним, чтобы соответствовать не пробел, за которым следует конец слова.
Someonewithpc
1
@ someonewithpc Нет, это не стандартно, поэтому я написал gnu sed . Приятно то, что вам не нужно обрабатывать первую и последнюю строку отдельно
Philippos
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там для новой строки)

ilkkachu
источник
Плюс один для awk! Я строил также решение awk просто для удовольствия. Есть небольшая вероятность того, что слова будут напечатаны в случайном порядке в секции END из-за случайного способа, которым awk повторяется в ключах массива.
Георгий
Да, они будут напечатаны в произвольном порядке. Однако 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

В Баш:

get_unique_words(){
  python -c "print ','.join(set('$1'.split(',')))"
}
wjandrea
источник
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)
Tododo Fly
источник
Пожалуйста, добавьте объяснение того, как работает ваш код и почему вы сделали то и это.
xhienne