ลบคำที่ซ้ำกันทั้งหมดออกจากสตริงโดยใช้เชลล์สคริปต์


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

มันทำงานได้ดีกับค่าเดียวกัน แต่เมื่อฉันให้ค่าตัวแปรแล้วมันจะแสดงคำที่ซ้ำกันทั้งหมดด้วย

ฉันจะลบค่าที่ซ้ำกันได้อย่างไร

UPDATE

คำถามของฉันคือการเพิ่มค่าที่สอดคล้องกันทั้งหมดลงในสตริงเดียวถ้าผู้ใช้เหมือนกันฉันมีข้อมูลเช่นนี้ ->

   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

ค่าสตริงมาแบบไดนามิก มันกำลังพิมพ์ค่าเดียวกัน (มีค่าซ้ำกัน)
Urvashi

1
ใช่แสดงรหัสที่ล้มเหลวมิฉะนั้นเราจะรู้ได้อย่างไรว่าเกิดอะไรผิดพลาดขึ้น
Sundeep

การสั่งซื้อมีความสำคัญหรือไม่
Jacob Vlijm

คำตอบ:


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เหตุผลก็คือว่าฉันกำลังทำเพื่อวนผ่านผลและช่องว่างสองสีขาวทำให้เกิดความท้าทายกับการแข่งขัน regex
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เพื่อเข้าร่วมเอาต์พุตหนึ่งบรรทัดอีกครั้ง
Philippos

4
sort -uหรือการใช้งาน awk '!u[$0]++หรือแม้กระทั่ง
Benoît

2
@ Benoîtว้าว, sort -uฉันไม่ทราบเกี่ยวกับ ฉันใช้มาsort | uniqตลอดเวลานี้ การกดแป้นที่สูญเปล่า ...
Gardenhead

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

1
ฉลาดมาก!!!!
George Vasiliou

@GeorgeVasiliou ขอบคุณ [หรือบอกความจริงขี้เกียจมาก :-)]
JJoao

2

ด้วย gnu sed:

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

คุณสามารถเพิ่ม;s/ */ /gเพื่อลบพื้นที่สาธารณะออก

ฟังก์ชั่นเช่นนี้: หากคำเป็นครั้งที่สองในบรรทัดนี้ให้ลบออกและเริ่มต้นใหม่จนกว่าจะไม่พบการเผยแพร่ซ้ำอีกต่อไป


สิ่งที่เป็น\<และ\>?
บางคนเท่านั้นที่มี

@someonewithpc พวกเขาไม่ตรงกับตัวอักษร แต่จุดเริ่มต้นและจุดสิ้นสุดของคำเพื่อป้องกันไม่ให้จับคู่สตริง
Philippos

ดี แต่พกพานั้น นอกจากนี้คำไม่คั่นด้วยช่องว่างหรือไม่ ดูเหมือนจะซ้ำซ้อนเพื่อให้ตรงกับช่องว่างไม่ตามด้วยท้ายคำ
บางคนเท่านั้นที่มี

1
@someonewithpc ไม่มีก็ไม่ได้มาตรฐานที่ว่าทำไมผมเขียนGNU sed ส่วนที่ดีคือคุณไม่ต้องจัดการสตริงตัวแรกและตัวสุดท้ายแยกจากกัน
Philippos

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

2

วิธีการแก้ปัญหาภาระผูกพัน:

$ 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! ฉันกำลังสร้างโซลูชัน awk เพียงเพื่อความสนุกสนาน มีคำที่เป็นไปได้เล็กน้อยที่จะพิมพ์ตามลำดับแบบสุ่มที่ส่วน END เนื่องจากวิธีการสุ่มที่ awk ซ้ำในคีย์อาร์เรย์
George Vasiliou

ใช่พวกเขาจะพิมพ์แบบสุ่มเป็นหลัก sortวิธีการแก้ปัญหาไม่ได้เก็บคำสั่งซื้อเดิมเช่นกัน
ilkkachu

ใช่จุดดี! แม้จะเรียงลำดับการพิมพ์ตามลำดับที่แตกต่างจากอินพุต
George Vasiliou

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

หรือคุณสามารถใช้มันเป็นฟังก์ชั่นทุบตี แต่ไวยากรณ์ยุ่งเหยิง

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ฟังก์ชันมาตรฐาน)
Kusalananda

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.