หากคุณใช้ Bash เวอร์ชัน 4 ขึ้นไป (ซึ่งควรเป็นเช่นนั้นใน Linux เวอร์ชันใหม่ ๆ ) คุณสามารถรับค่าอาร์เรย์ที่ไม่ซ้ำกันใน bash ได้โดยการสร้างอาร์เรย์ที่เชื่อมโยงใหม่ซึ่งมีค่าแต่ละค่าของอาร์เรย์เดิม สิ่งนี้:
$ a=(aa ac aa ad "ac ad")
$ declare -A b
$ for i in "${a[@]}"; do b["$i"]=1; done
$ printf '%s\n' "${!b[@]}"
ac ad
ac
aa
ad
สิ่งนี้ใช้ได้ผลเพราะในอาร์เรย์ใด ๆ (เชื่อมโยงหรือดั้งเดิมในภาษาใดก็ได้) แต่ละคีย์จะปรากฏได้เพียงครั้งเดียว เมื่อfor
วงมาถึงที่คุ้มค่าที่สองของaa
ในa[2]
ก็เขียนทับซึ่งเป็นชุดเดิมสำหรับb[aa]
a[0]
การทำสิ่งต่างๆด้วยการทุบตีแบบดั้งเดิมทำได้เร็วกว่าการใช้ไปป์และเครื่องมือภายนอกเช่นsort
และuniq
แม้ว่าสำหรับชุดข้อมูลขนาดใหญ่คุณจะเห็นประสิทธิภาพที่ดีขึ้นหากคุณใช้ภาษาที่มีประสิทธิภาพมากขึ้นเช่น awk, python เป็นต้น
ถ้าคุณรู้สึกมั่นใจคุณสามารถหลีกเลี่ยงfor
วงโดยใช้ความสามารถที่จะนำรูปแบบสำหรับอาร์กิวเมนต์หลายแม้เรื่องนี้ดูเหมือนว่าจะต้องprintf
eval
(หยุดอ่านตอนนี้ถ้าคุณสบายดี)
$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") )
$ declare -p b
declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
เหตุผลที่โซลูชันนี้ต้องการeval
คือค่าอาร์เรย์จะถูกกำหนดก่อนการแยกคำ นั่นหมายความว่าเอาต์พุตของการแทนที่คำสั่งถือเป็นคำเดี่ยวแทนที่จะเป็นชุดของคู่คีย์ = ค่า
แม้ว่าจะใช้ subshell แต่ก็ใช้ bash builtins เท่านั้นในการประมวลผลค่าอาร์เรย์ อย่าลืมประเมินการใช้งานของคุณeval
ด้วยสายตาที่สำคัญ หากคุณไม่มั่นใจ 100% ว่า chepner หรือ glenn jackman หรือ greycat จะไม่พบข้อผิดพลาดกับรหัสของคุณให้ใช้ for loop แทน
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"