Kabuk betiğini kullanarak dizeden tüm yinelenen sözcükleri kaldır


12

Benim gibi bir ipim var

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

Dize yinelenen kelime kaldırmak istiyorum sonra çıktı gibi olacak

"aaa,bbb,ccc"

Bu kodu denedim Kaynak

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

Aynı değerle iyi çalışıyor, ancak değişken değerimi verdiğimde tüm yinelenen kelimeleri de gösteriyor.

Yinelenen değeri nasıl kaldırabilirim.

GÜNCELLEME

Benim sorum kullanıcı aynı ise tek bir dize karşılık gelen tüm değer eklemektir. Böyle veri var ->

   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

Kodlama ben tüm farklı kullanıcı getir sonra başarıyla renk dizesini bitiştirmek. Bunun için kod kullanıyorum -

while read the records 

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

Bu $ c değişkenini yazdırdığımda çıktı alıyorum (Kullanıcı AAA için)

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

Yinelenen rengi kaldırmak istiyorum.

"red,black,blue,green"

Bu istenen çıkış için yukarıdaki kod kullanılır

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

ancak çıktı yinelenen değerlerle görüntüleniyor.

"kırmızı, siyah, mavi, kırmızı, yeşil, kırmızı, siyah, mavi, kırmızı, yeşil," Teşekkürler


3
Lütfen neyi kullandığınızla ilgili sorununuzu netleştirin. "Değişken değerimi verdiğimde" ne demek istediğini anlamıyorum. Ne değer veriyorsunuz? Nerede başarısız oluyor?
terdon

echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsverir aaa bbb ccc.. bu yüzden yorgun ve var tam kodunu göstermek gerekir .. değişkente dize ile:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

dize değeri dinamik olarak gelir. Aynı değeri yazdırıyor (yinelenen değer içeriyor).
Urvashi

1
evet, başarısız olan kodu göster, yoksa neyin yanlış gidebileceğini nasıl bilebilirdik?
Sundeep

Sipariş önemli mi?
Jacob Vlijm

Yanıtlar:


12

Bir eğlence daha, sadece eğlence için:

$ 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 

Bu arada, çözümünüz bile değişkenlerle iyi çalışır:

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

Düzgün bir yaklaşım. Yapmam gereken tek ayar %syerine kullanmaktı %s%s. Bunun nedeni, sonuçlarda bir for döngüsü yapmam ve iki beyaz boşluğun regex maçlarında bazı zorluklara neden olmasıydı.
JeremyCanfield

9

İle tr, sortveuniq

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

veya

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

bir satır almak


| xargsÇıktıyı bir satıra tekrar katılmak için eklemeniz gerekiyor
Philippos

4
Veya kullanın sort -u. Hatta bir awk '!u[$0]++.
Benoît

2
@ Benoît Wow, bilmiyordum sort -u. Bunca zamandır kullanıyorum sort | uniq. Boşa giden tuş vuruşları ...
gardenhead

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

1
Çok zeki!!!!
George Vasiliou

@GeorgeVasiliou, teşekkür ederim [ya da doğruyu söylemek gerekirse, çok tembel :-)]
JJoao

2

GNU ile sed:

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

Genel ;s/ */ /galanları kaldırmak için ekleyebilirsiniz .

Bunun gibi işlevler: Bir kelime bu satırda ikinci kez ise, kelimeyi kaldırın ve artık hiçbir yayın bulunmayana kadar yeniden başlayın.


Nedir \<ve \>?
birisi

@someonewithpc Alt karakterlerin eşleşmesini önlemek için hiçbir karakter değil, bir sözcüğün başlangıcı ve bitişi ile eşleşirler.
Philippos

Güzel, ama taşınabilir mi? Ayrıca, kelimeler boşlukla ayrılmış değil mi? Beyaz boşluktan sonra bir kelimenin sonuna kadar eşleşmesi gereksiz görünüyor.
birisi

1
@someonewithpc Hayır, standart değil, bu yüzden gnu sed yazdım . Güzel kısım, ilk ve son ipi ayrı ayrı ele almanıza gerek olmamasıdır
Philippos

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

2

Zorunlu awk çözümü:

$ 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 

(Final echoyeni satır için var)


Ayrıca awk için bir tane! Ben de sadece eğlence için awk bir çözüm inşa edildi. Dizi anahtarlarında awk yinelemesinin rastgele yolu nedeniyle END bölümünde rastgele sırada yazdırılacak küçük bir olasılık sözcüğü vardır.
George Vasiliou

Evet, bunlar esasen rastgele bir sırayla yazdırılacaktır. sortÇözelti olsa ya orijinal siparişi tutmaz.
ilkkachu

Evet, iyi bir nokta! Hatta baskıları girişten farklı sırada sıralayın.
George Vasiliou

1
@ilkkachu Aslında girdinin bitmesini beklememiz gerekmiyor. Kodunuzda küçük bir değişiklik yaparak yazdırmaya veya yazdırmamaya karar verebiliriz: awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoBu, siparişi korur.

1

piton

seçenek 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)

Yürütülebilir yapın, sonra Bash'ten arayın:

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

Veya bir Bash işlevi olarak uygulayabilirsiniz, ancak sözdizimi dağınıktır.

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

seçenek 2

Bu seçenek gerekirse tek astar olabilir:

#!/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'ta:

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

Ben alamadım
Pierre.Vriens

1
Kodunuzda açıklama yok. Hiçbir açıklama yapmadan, olanları takip etmek zor. Ayrıca, yanlış görünen veriler (boşlukla ayrılmış alanlar) ve awkkullanılan belirli uygulama hakkında ( asorti()standart bir awkişlev değildir ) varsayımlar yapmış gibi görünüyorsunuz .
Kusalananda

0

Dosyadaki orijinal tablo verilerinin kullanılması file:

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

Bu üretir

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

Boru hattının üç adımı:

  1. sedKomut Okuduğumuz istemiyoruz ki üstbilgidir ilk satırı kaldırır.
  2. sortKomut bize benzersiz satırları verir. sortGörünüşe göre örnek veriler

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
  3. awkKomut bu verileri alır ve dizideki her bir kullanıcı için bir virgülle ayrılmış dize üretir color(kullanıcı adı diziye anahtardır). Sonunda ( ENDblokta) toplanan tüm veriler çıkarılır.

-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)

Lütfen kodunuzun nasıl çalıştığına ve bunu neden yaptığınıza ilişkin bir açıklama ekleyin.
xhienne
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.