Trái với ksh hoặc zsh, bash không có hỗ trợ dựng sẵn để sắp xếp các mảng hoặc danh sách các chuỗi tùy ý. Nó có thể sắp xếp những đống hoặc đầu ra của alias
hay set
hay typeset
(mặc dù những cuối cùng 3 không trong thứ tự sắp xếp locale của người dùng), nhưng điều đó có thể không được sử dụng thực tế ở đây.
Không có gì trong bộ công cụ POSIX có thể dễ dàng sắp xếp danh sách các chuỗi tùy ý ( sort
sắp xếp các dòng, do đó, chỉ các chuỗi ký tự ngắn (LINE_MAX thường ngắn hơn PATH_MAX) ngoài NUL và dòng mới, trong khi các đường dẫn tệp không phải là chuỗi byte khác hơn 0).
Vì vậy, trong khi bạn có thể thực hiện thuật toán sắp xếp của riêng mình trong awk
(sử dụng <
toán tử so sánh chuỗi) hoặc thậm chíbash
(sử dụng [[ < ]]
), đối với các đường dẫn tùy ý bash
, có thể dễ dàng nhất là sử dụng perl
:
Với bash4.4+
, bạn có thể làm:
readarray -td '' sorted_filearray < <(perl -MFile::Basename -l0 -e '
print for sort {basename($a) cmp basename($b)} @ARGV' -- "${filearray[@]}")
Điều đó mang lại một strcmp()
trật tự giống như. Đối với một đơn hàng dựa trên các quy tắc đối chiếu của miền địa phương như trong các khối hoặc đầu ra của ls
, hãy thêm một -Mlocale
đối số vào perl
. Đối với sắp xếp số (giống như GNU sort -g
vì nó hỗ trợ các số như +3
, 1.2e-5
chứ không phải hàng nghìn dấu phân cách, mặc dù không phải là hexadimals), hãy sử dụng <=>
thay vì cmp
(và một lần nữa -Mlocale
để dấu thập phân của người dùng được tôn vinh như sort
lệnh).
Bạn sẽ bị giới hạn bởi kích thước tối đa của các đối số cho một lệnh. Để tránh điều đó, bạn có thể chuyển danh sách các tệp perl
vào stdin của nó thay vì thông qua các đối số:
readarray -td '' sorted_filearray < <(
printf '%s\0' "${filearray[@]}" | perl -MFile::Basename -0le '
chomp(@files = <STDIN>);
print for sort {basename($a) cmp basename($b)} @files')
Với các phiên bản cũ hơn bash
, bạn có thể sử dụng while IFS= read -rd ''
vòng lặp thay vì readarray -d ''
hoặc perl
xuất ra danh sách các đường dẫn được trích dẫn chính xác để bạn có thể chuyển nó tới eval "array=($(perl...))"
.
Với zsh
, bạn có thể giả mạo một bản mở rộng toàn cầu mà bạn có thể xác định thứ tự sắp xếp:
sorted_filearray=(/(e{'reply=($filearray)'}oe{'REPLY=$REPLY:t'}))
Với reply=($filearray)
chúng tôi thực sự buộc việc mở rộng toàn cầu (mà ban đầu chỉ là /
) là các yếu tố của mảng. Sau đó, chúng tôi xác định thứ tự sắp xếp dựa trên đuôi của tên tệp.
Đối với một strcmp()
thứ tự giống như, sửa lỗi miền địa phương thành C. Đối với sắp xếp số (tương tự GNU sort -V
, không sort -n
tạo ra sự khác biệt đáng kể khi so sánh 1.4
và 1.23
( .
ví dụ, trong đó là dấu thập phân), hãy thêm vào n
vòng loại toàn cầu.
Thay vì oe{expression}
, bạn cũng có thể sử dụng một hàm để xác định thứ tự sắp xếp như:
by_tail() REPLY=$REPLY:t
hoặc những cái cao cấp hơn như:
by_numbers_in_tail() REPLY=${(j:,:)${(s:,:)${REPLY:t}//[^0-9]/,}}
(vì vậy a/foo2bar3.pdf
(2,3 số) sắp xếp sau b/bar1foo3.pdf
(1,3) nhưng trước c/baz2zzz10.pdf
(2,10)) và sử dụng như:
sorted_filearray=(/(e{'reply=($filearray)'}no+by_numbers_in_tail))
Tất nhiên, những thứ đó có thể được áp dụng trên các quả bóng thực sự vì đó là những gì chúng chủ yếu dành cho. Chẳng hạn, đối với danh sách các pdf
tệp trong bất kỳ thư mục nào, được sắp xếp theo tên cơ sở / đuôi:
pdfs=(**/*.pdf(N.oe+by_tail))
Nếu strcmp()
việc sắp xếp dựa trên cơ sở có thể chấp nhận được và đối với các chuỗi ngắn, bạn có thể chuyển đổi các chuỗi thành mã hóa hex của chúng awk
trước khi chuyển đến sort
và chuyển đổi trở lại sau khi sắp xếp.