Lọc một mảng rất khó nếu bạn xem xét khả năng chứa các phần tử (không kể các ký tự "weirder"). Trong các câu trả lời cụ thể cho đến nay (đề cập đến các hình thức khác nhau của ${x[@]//pref*/}
) sẽ không thành công với các mảng như vậy.
Tôi đã điều tra vấn đề này một chút và tìm ra giải pháp tuy nhiên nó không phải là một lớp lót đẹp. Nhưng ít nhất nó là.
Ví dụ minh họa giả sử arr
đặt tên mảng mà chúng tôi muốn lọc. Chúng ta sẽ bắt đầu với các biểu hiện cốt lõi:
for index in "${!ARR[@]}" ; do [[ …condition… ]] && unset -v 'ARR[$index]' ; done
ARR=("${ARR[@]}")
Hiện đã có vài yếu tố đáng nói:
"${!ARR[@]}"
để đánh giá chỉ số của mảng (như trái ngược với các yếu tố).
- Biểu mẫu
"${!ARR[@]}"
là điều bắt buộc. Bạn không được bỏ qua báo giá hoặc thay đổi @
thành *
. Hoặc người nào khác biểu thức sẽ phá vỡ trên mảng kết hợp, nơi các phím có dấu cách (ví dụ).
- Phần sau
do
có thể là bất kỳ thứ gì bạn muốn. Ý tưởng chỉ là bạn phải làm unset
như được hiển thị cho các phần tử mà bạn không muốn có trong mảng.
- It is advised or even needed để sử dụng
-v
và báo giá với unset
hoặc những điều xấu khác có thể xảy ra.
- Nếu phần sau
do
như được đề xuất ở trên, bạn có thể sử dụng &&
hoặc ||
để lọc ra các yếu tố vượt qua hoặc thất bại điều kiện.
- Dòng thứ hai, chỉ định lại
ARR
, chỉ cần thiết với các mảng không liên kết và sẽ phá vỡ với mảng liên kết. (Tôi đã không nhanh chóng đưa ra một biểu thức chung mà sẽ xử lý cả trong khi tôi không cần một…). Đối với các mảng thông thường, nó là cần thiết nếu bạn muốn có các chỉ mục liên tiếp.Bởi vì unset
trên một phần tử mảng không sửa đổi (giảm một) các phần tử của các chỉ mục cao hơn - nó chỉ làm cho một lỗ trong các chỉ mục. Bây giờ nếu bạn chỉ lặp qua mảng (hoặc mở rộng nó như một toàn thể) điều này làm cho không có vấn đề. Nhưng đối với các trường hợp khác, bạn cần gán lại các chỉ mục. Cũng lưu ý rằng nếu bạn có bất kỳ lỗ nào trong các chỉ mục trước khi nó cũng bị xóa. Vì vậy, nếu bạn cần bảo tồn các lỗ hiện có, cần phải thực hiện nhiều logic hơn bên cạnh số unset
và giao lại lần cuối.
Hiện tại vì điều kiện này. Biểu thức [[ ]]
là một cách dễ dàng nếu bạn có thể sử dụng nó. (Xem here.) Cụ thể là nó hỗ trợ đối sánh cụm từ thông dụng bằng cách sử dụng Extended Regular Expressions. (Xem here.) Cũng phải cẩn thận khi sử dụng grep
hoặc bất kỳ công cụ dựa trên dòng nào khác cho điều này nếu bạn mong đợi rằng các phần tử mảng có thể chứa không chỉ các khoảng trống mà còn có các dòng mới. (Trong khi một tên tập tin rất khó chịu có thể có một ký tự dòng mới Tôi nghĩ ...)
Đề cập đến vấn đề bản thân khái niệm [[ ]]
sẽ phải là:
[[ ${ARR[$index]} =~ ^pref ]]
(với && unset
như trên)
Cuối cùng hãy xem cách điều này hoạt động với những trường hợp khó khăn đó. Đầu tiên chúng ta xây dựng các mảng:
declare -a ARR='([0]="preffoo" [1]="bar" [2]="foo" [3]="prefbaz" [4]="baz" [5]="prefbar" [6]="pref with spaces")'
ARR+=($'pref\nwith\nnew line')
ARR+=($'\npref with new line before')
chúng ta có thể thấy rằng chúng tôi có tất cả các trường hợp phức tạp bằng cách chạy declare -p ARR
và nhận được:
declare -a ARR='([0]="preffoo" [1]="bar" [2]="foo" [3]="prefbaz" [4]="baz" [5]="prefbar" [6]="pref with spaces" [7]="pref
with
new line" [8]="
pref with new line before")'
Bây giờ chúng ta chạy các biểu thức lọc:
for index in "${!ARR[@]}" ; do [[ ${ARR[$index]} =~ ^pref ]] && unset -v 'ARR[$index]' ; done
và một thử nghiệm khác (declare -p ARR
) cho dự kiến:
declare -a ARR='([1]="bar" [2]="foo" [4]="baz" [8]="
pref with new line before")'
lưu ý cách tất cả các phần tử bắt đầu bằng pref
đã bị xóa nhưng các chỉ mục không thay đổi. Cũng lưu ý rằng ${ARRAY[8]}
vẫn còn ở đó vì nó bắt đầu bằng dòng mới thay vì pref
.
Bây giờ cho các giao lại cuối cùng:
ARR=("${ARR[@]}")
và kiểm tra (declare -p ARR
):
declare -a ARR='([0]="bar" [1]="foo" [2]="baz" [3]="
pref with new line before")'
đó là chính xác những gì được mong đợi.
Để ghi chú đóng. Nó sẽ được tốt đẹp nếu điều này có thể được thay đổi thành một lớp lót linh hoạt. Nhưng tôi không nghĩ rằng có một cách để làm cho nó ngắn hơn và đơn giản hơn như bây giờ mà không cần định nghĩa hàm hay giống nhau.
Đối với các chức năng nó sẽ được tốt đẹp cũng như có nó chấp nhận mảng, mảng trở lại và có dễ dàng để cấu hình thử nghiệm để loại trừ hoặc giữ. Nhưng tôi không đủ tốt với Bash để làm điều đó ngay bây giờ.
+1 cảm ơn vì đã xóa bỏ sự nhầm lẫn từ bài đăng của Hulk và chỉ ra con đường khác này. – kynan