Hapus semua kata duplikat dari string menggunakan skrip shell

12

Saya punya string seperti

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

Saya ingin menghapus duplikat kata dari string maka hasilnya akan seperti

"aaa,bbb,ccc"

Saya mencoba Sumber kode ini

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

Ini berfungsi dengan baik dengan nilai yang sama, tetapi ketika saya memberikan nilai variabel saya maka itu menunjukkan semua kata duplikat juga.

Bagaimana saya bisa menghapus nilai duplikat.

MEMPERBARUI

Pertanyaan saya adalah menambahkan semua nilai yang sesuai ke dalam string tunggal jika pengguna sama. Saya punya data seperti ini ->

   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

Dalam pengkodean saya mengambil semua pengguna yang berbeda maka saya berhasil merangkai string warna. Untuk itu saya menggunakan kode -

while read the records 

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

Ketika saya mencetak variabel $ c ini saya mendapatkan output (Untuk Pengguna AAA)

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

Saya ingin menghapus warna duplikat. Maka output yang diinginkan harus seperti

"red,black,blue,green"

Untuk output yang diinginkan ini saya menggunakan kode di atas

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

tetapi menampilkan output dengan nilai duplikat .Seperti

"merah, hitam, biru, merah, hijau, merah, hitam, biru, merah, hijau," Terima kasih

Urvashi
sumber
3
Harap jelaskan apa yang salah dengan apa yang Anda gunakan. Saya tidak mengerti apa yang Anda maksud dengan "ketika saya memberikan nilai variabel saya". Nilai apa yang Anda berikan? Di mana itu gagal?
terdon
echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsmemberikan aaa bbb ccc.. jadi Anda harus menunjukkan kode yang tepat Anda lelah dan output yang Anda dapatkan .. dengan string dalam variabel:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep
nilai string datang secara dinamis. Ini mencetak nilai yang sama (mengandung nilai duplikat).
Urvashi
1
ya, tunjukkan kode yang gagal, jika tidak, bagaimana kita tahu apa yang salah?
Sundeep
Apakah pesanan itu penting?
Jacob Vlijm

Jawaban:

12

Satu lagi awk, hanya untuk bersenang-senang:

$ 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 

Omong-omong, bahkan solusi Anda berfungsi dengan baik dengan variabel:

$ b="zebra ant spider spider ant zebra ant" 
$ echo "$b" | xargs -n1 | sort -u | xargs
ant spider zebra
George Vasiliou
sumber
Pendekatan yang rapi. Satu-satunya penyesuaian yang harus saya lakukan adalah menggunakan %salih-alih %s%s. Alasannya adalah bahwa saya melakukan loop for melalui hasil dan dua spasi putih menyebabkan beberapa tantangan dengan pertandingan regex.
JeremyCanfield
9

Dengan tr, sortdanuniq

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

atau

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

untuk mendapatkan satu baris

Michael D.
sumber
Anda perlu menambahkan | xargsuntuk bergabung dengan output ke satu baris lagi
Philippos
4
Atau gunakan sort -u. Atau bahkan a awk '!u[$0]++.
Benoît
2
@ Benoît Wow, saya tidak tahu sort -u. Saya telah menggunakan sort | uniqselama ini.
Keystrokes yang
8
$ echo "zebra ant spider spider ant zebra ant"  | awk -v RS="[ \n]+" '!n[$0]++' 
zebra
ant
spider
Joao
sumber
1
Sangat pintar!!!!
George Vasiliou
@ GeorgeVasiliou, terima kasih [atau sejujurnya, sangat malas :-)]
JJoao
2

Dengan gnu sed:

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

Anda dapat menambahkan ;s/ */ /guntuk menghapus ruang dublicate.

Fungsi seperti ini: Jika sebuah kata adalah yang kedua kalinya di baris ini, hapus dan mulai lagi sampai tidak ada publikasi yang ditemukan lagi.

Filipos
sumber
Apa \<dan \>?
someonewithpc
@someonewithpc Mereka tidak cocok dengan karakter, tetapi awal dan akhir kata untuk mencegah substring dicocokkan.
Philippos
Bagus, tapi apakah itu portabel? Juga, bukankah kata-kata dipisahkan oleh spasi? Tampaknya berlebihan untuk mencocokkan bukan spasi putih diikuti oleh akhir kata.
someonewithpc
1
@someonewithpc Tidak, ini bukan standar, itu sebabnya saya menulis gnu sed . Bagian yang menyenangkan adalah Anda tidak perlu menangani string pertama dan terakhir secara terpisah
Philippos
2
perl -lane '$,=$";print grep { ! $h{$_}++ } @F'

sumber
2

Solusi awk wajib:

$ 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 echoada di sana untuk baris baru)

ilkkachu
sumber
Plus satu untuk awk! Saya membangun juga solusi awk hanya untuk bersenang-senang. Ada sedikit kemungkinan kata-kata yang akan dicetak dalam urutan acak di bagian AKHIR karena cara acak yang awter itterate dalam kunci array.
George Vasiliou
Ya, mereka akan dicetak dalam urutan yang pada dasarnya acak. The sortsolusi tidak menyimpan urutan asli baik, meskipun.
ilkkachu
Ya, poin bagus! Bahkan mengurutkan cetakan dalam urutan berbeda dari input.
George Vasiliou
1
@ilkkachu Sebenarnya kita tidak perlu menunggu input berakhir. Kami dapat membuat keputusan untuk mencetak atau tidak mencetak dengan sedikit modifikasi pada kode Anda: awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoIni menjaga pesanan.
1

Python

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

Jadikan dapat dieksekusi, lalu panggil dari Bash:

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

Atau Anda bisa mengimplementasikannya sebagai fungsi Bash, tetapi sintaksnya berantakan.

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

pilihan 2

Opsi ini dapat menjadi satu garis jika diperlukan:

#!/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

Di Bash:

get_unique_words(){
  python -c "print ','.join(set('$1'.split(',')))"
}
wjandrea
sumber
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
天津 神 こ と
sumber
Saya tidak mengerti
Pierre.Vriens
1
Kode Anda kurang penjelasan. Tanpa penjelasan, sulit untuk mengikuti apa yang terjadi. Anda juga tampaknya membuat asumsi tentang data yang tampaknya salah (bidang yang dibatasi spasi) dan tentang awkimplementasi tertentu yang digunakan ( asorti()bukan awkfungsi standar ).
Kusalananda
0

Menggunakan data tabular asli dalam file bernama file:

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

Ini menghasilkan

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

Tiga langkah dari pipa:

  1. The sedperintah menghilangkan baris pertama yang merupakan header yang kita tidak ingin membaca.
  2. The sortperintah memberi kita garis yang unik. Sampel data setelah sortterlihat seperti

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
    
  3. The awkperintah mengambil data ini dan menghasilkan string koma-delimited untuk setiap pengguna dalam array color(dimana username adalah kunci ke dalam array). Pada akhirnya (di ENDblok), semua data yang dikumpulkan dikeluarkan.
Kusalananda
sumber
-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
sumber
Harap tambahkan penjelasan tentang cara kerja kode Anda dan mengapa Anda melakukan ini dan itu.
xhienne