Xóa tất cả từ trùng lặp khỏi chuỗi bằng shell script


12

Tôi có một chuỗi như

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

Tôi muốn xóa từ trùng lặp khỏi chuỗi thì đầu ra sẽ như thế nào

"aaa,bbb,ccc"

Tôi đã thử mã nguồn này

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

Nó hoạt động tốt với cùng một giá trị, nhưng khi tôi đưa ra giá trị biến của mình thì nó cũng hiển thị tất cả các từ trùng lặp.

Làm thế nào tôi có thể loại bỏ giá trị trùng lặp.

CẬP NHẬT

Câu hỏi của tôi là thêm tất cả giá trị tương ứng vào một chuỗi nếu người dùng giống nhau. Tôi có dữ liệu như thế này ->

   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

Trong mã hóa, tôi tìm nạp tất cả người dùng riêng biệt sau đó tôi nối chuỗi màu thành công. Tôi đang sử dụng mã -

while read the records 

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

Khi tôi in biến $ c này, tôi nhận được đầu ra (Dành cho Người dùng AAA)

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

Tôi muốn loại bỏ màu trùng lặp. Sau đó, đầu ra mong muốn sẽ giống như

"red,black,blue,green"

Đối với đầu ra mong muốn này, tôi đã sử dụng mã ở trên

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

nhưng nó đang hiển thị đầu ra với các giá trị trùng lặp. Giống như

"đỏ, đen, xanh dương, đỏ, xanh lá cây, đỏ, đen, xanh dương, đỏ, xanh lá cây," Cảm ơn


3
Hãy làm rõ những gì sai với những gì bạn đang sử dụng. Tôi không hiểu ý của bạn là "khi tôi đưa ra giá trị biến". Bạn cho giá trị gì? Nó thất bại ở đâu?
terdon

echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargscho aaa bbb ccc.. vì vậy bạn cần hiển thị chính xác mã bạn mệt mỏi và đầu ra bạn nhận được .. với chuỗi biến:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

giá trị chuỗi đến động. Đó là in cùng một giá trị (chứa giá trị trùng lặp).
Urvashi

1
yeah, hiển thị mã bị lỗi, nếu không thì làm sao chúng ta biết điều gì có thể sai?
Sundeep

Liệu thứ tự có vấn đề?
Jacob Vlijm

Câu trả lời:


12

Thêm một lần nữa, chỉ để cho vui:

$ 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 

Nhân tiện, ngay cả giải pháp của bạn cũng hoạt động tốt với các biến:

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

Cách tiếp cận gọn gàng. Điều chỉnh duy nhất tôi phải thực hiện là sử dụng %sthay vì %s%s. Lý do là tôi đã thực hiện một vòng lặp thông qua kết quả và hai khoảng trắng gây ra một số thách thức với các trận đấu regex.
JeremyCanfield

9

Với tr, sortuniq

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

hoặc là

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

để có được một dòng


Bạn cần thêm | xargsđể tham gia đầu ra một lần nữa
Philippos

4
Hoặc sử dụng sort -u. Hoặc thậm chí là a awk '!u[$0]++.
Benoît

2
@ Benoît Wow, tôi không biết về sort -u. Tôi đã sử dụng sort | uniqtất cả thời gian này. Các tổ hợp phím bị lãng phí ...
vườn

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

1
Rất thông minh!!!!
George Vasiliou

@GeorgeVasiliou, cảm ơn bạn [hoặc nói thật, rất lười biếng :-)]
JJoao

2

Với gnu sed:

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

Bạn có thể thêm ;s/ */ /gđể loại bỏ không gian công khai.

Các chức năng như thế này: Nếu một từ là lần thứ hai trong dòng này, hãy xóa nó và bắt đầu lại cho đến khi không tìm thấy sự phân phối nữa.


Là gì \<\>?
someonewithpc

@someonewithpc Chúng không khớp với ký tự, nhưng bắt đầu và kết thúc của một từ để ngăn các chuỗi con không khớp.
Philippos

Đẹp, nhưng đó là di động? Ngoài ra, không phải các từ được phân tách bằng khoảng trắng? Có vẻ dư thừa để khớp không phải khoảng trắng theo sau là kết thúc của một từ.
someonewithpc

1
@someonewithpc Không, nó không chuẩn, đó là lý do tại sao tôi viết gnu sed . Phần thú vị là bạn không phải xử lý riêng chuỗi đầu tiên và cuối cùng
Philippos

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

2

Giải pháp awk bắt buộc:

$ 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 

(Trận chung kết echolà có cho dòng mới)


Thêm một cho awk! Tôi đã xây dựng một giải pháp awk chỉ để cho vui. Có một từ khả năng nhỏ sẽ được in theo thứ tự ngẫu nhiên trong phần END do cách ngẫu nhiên đánh thức nó trong các khóa mảng.
George Vasiliou

Vâng, chúng sẽ được in theo thứ tự cơ bản ngẫu nhiên. Tuy nhiên, sortgiải pháp không giữ nguyên thứ tự ban đầu.
ilkkachu

Vâng, điểm tốt! Thậm chí sắp xếp in theo thứ tự khác với đầu vào.
George Vasiliou

1
@ilkkachu Thật ra chúng ta không cần đợi đầu vào kết thúc. Chúng tôi có thể đưa ra quyết định in hoặc không in với một sửa đổi nhỏ cho mã của bạn: awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoĐiều này bảo toàn thứ tự.

1

Con trăn

lựa chọn 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)

Thực hiện, sau đó gọi từ Bash:

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

Hoặc bạn có thể thực hiện nó như một hàm Bash, nhưng cú pháp thì lộn xộn.

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

Lựa chọn 2

Tùy chọn này có thể trở thành một lớp lót nếu cần:

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

Trong 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

Tôi không hiểu điều đó
Pierre.Vriens

1
Mã của bạn thiếu giải thích. Không có lời giải thích, thật khó để theo dõi những gì đang xảy ra. Bạn dường như cũng đưa ra các giả định về dữ liệu có vẻ sai (các trường được phân tách bằng khoảng trắng) và về việc awktriển khai cụ thể đang được sử dụng ( asorti()không phải là một awkhàm chuẩn ).
Kusalananda

0

Sử dụng dữ liệu bảng gốc trong tệp có tên file:

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

Điều này tạo ra

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

Ba bước của đường ống:

  1. Các sedlệnh loại bỏ dòng đầu tiên mà là một tiêu đề mà chúng tôi không muốn đọc.
  2. Các sortlệnh cho chúng ta đường độc đáo. Dữ liệu mẫu sau khi sorttrông giống như

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
  3. Các awklệnh mất dữ liệu này và tạo ra một chuỗi dấu phẩy phân cách cho mỗi người dùng trong mảng color(nơi tên người dùng chính là chìa khóa thành mảng). Vào cuối (trong ENDkhối), tất cả dữ liệu thu thập được xuất ra.

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

Vui lòng thêm một lời giải thích về cách mã của bạn hoạt động và lý do tại sao bạn làm điều này và điều đó.
xhienne
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.