Nếu bạn đang chạy phiên bản Bash 4 trở lên (trường hợp này xảy ra trong bất kỳ phiên bản Linux hiện đại nào), bạn có thể nhận các giá trị mảng duy nhất trong bash bằng cách tạo một mảng kết hợp mới chứa từng giá trị của mảng ban đầu. Một cái gì đó như thế này:
$ 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
Điều này hoạt động vì trong bất kỳ mảng nào (liên kết hoặc truyền thống, bằng bất kỳ ngôn ngữ nào), mỗi khóa chỉ có thể xuất hiện một lần. Khi for
vòng lặp đến giá trị thứ hai của aa
in a[2]
, nó sẽ ghi đè giá trị b[aa]
được đặt ban đầu cho a[0]
.
Thực hiện mọi thứ trong native bash có thể nhanh hơn so với việc sử dụng các đường dẫn và các công cụ bên ngoài như sort
và uniq
, mặc dù đối với các bộ dữ liệu lớn hơn, bạn có thể sẽ thấy hiệu suất tốt hơn nếu bạn sử dụng một ngôn ngữ mạnh mẽ hơn như awk, python, v.v.
Nếu bạn cảm thấy tự tin, bạn có thể tránh for
vòng lặp bằng cách sử dụng printf
khả năng tái chế định dạng của nó cho nhiều đối số, mặc dù điều này dường như yêu cầu eval
. (Ngừng đọc ngay bây giờ nếu bạn thấy ổn với điều đó.)
$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") )
$ declare -p b
declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
Lý do giải pháp này yêu cầu eval
là các giá trị mảng được xác định trước khi tách từ. Điều đó có nghĩa là đầu ra của lệnh thay thế được coi là một từ duy nhất chứ không phải là một tập hợp các cặp key = value.
Trong khi điều này sử dụng một vỏ con, nó chỉ sử dụng nội trang cơ sở để xử lý các giá trị mảng. Hãy chắc chắn để đánh giá việc sử dụng của bạn eval
với một con mắt quan trọng. Nếu bạn không chắc chắn 100% rằng chepner hoặc glenn jackman hoặc greycat sẽ không tìm thấy lỗi nào với mã của bạn, hãy sử dụng vòng lặp for.
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"