Видаліть усі повторювані слова з рядка за допомогою скрипта оболонки


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 | xargsдає aaa bbb ccc.. тож вам потрібно показати точний код, який вам набрид, і виведіть у вас .. рядок у змінній:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

значення рядка надходить динамічно. Це друк однакового значення (містить повторюване значення).
Урваші

1
так, покажіть код, який не вдався, інакше як ми могли знати, що могло піти не так?
Сундіп

Чи має значення замовлення?
Яків Влійм

Відповіді:


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. Причина полягає в тому, що я робив цикл за результатами, і два пробіли викликали певні труднощі при поєднанні з регулярними виразками.
JeremyCanfield

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щоб знову приєднати висновок до одного рядка
Філіпос

4
Або використовувати sort -u. Або навіть а awk '!u[$0]++.
Беньот

2
@ Benoît Wow, про що я не знав sort -u. Я sort | uniqвесь цей час використовую.
Даремно

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

1
Дуже розумний!!!!
Джордж

@GeorgeVasiliou, дякую [або правду кажучи, дуже лінивий :-)]
JJoao

2

З гну sed:

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

Ви можете додати ;s/ */ /gдля видалення дублікатів пробілів.

Функції, подібні до цієї: Якщо слово вдруге в цьому рядку, видаліть його та починайте спочатку, поки не буде знайдено жодного дублювання.


Що таке \<і \>?
whowithpc

@someonewithpc Вони не відповідають жодному символу, але початок і кінець слова, щоб запобігти збігу підрядків.
Філіппос

Приємно, але це портативно? Також, чи не розділені слова пробілом? Здається, що це зайве, щоб не збігнути пробіл з наступним кінцем слова.
whowithpc

1
@someonewithpc Ні, це не стандартно, тому я написав gnu sed . Приємно, що вам не потрібно обробляти першу та останню струну окремо
Філіпос,

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! Я будував також дивовижне рішення просто для розваги. Існує невелика можливість слів друкувати у випадковому порядку в розділі 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.