Không có cách nào để bảo vệ không gian trong bản mở rộng backtick (hoặc $ (...))?
Không, không có. Tại sao vậy?
Bash không có cách nào để biết những gì nên được bảo vệ và những gì không nên.
Không có mảng trong tệp / ống unix. Nó chỉ là một luồng byte. Lệnh bên trong ``
hoặc $()
xuất ra một luồng, nó sẽ nuốt và xử lý như một chuỗi đơn. Như vậy, bạn chỉ có hai lựa chọn: đặt nó trong dấu ngoặc kép, để giữ nó thành một chuỗi hoặc đặt nó ở chế độ trần, để bash chia nó ra theo hành vi được cấu hình của nó.
Vì vậy, những gì bạn phải làm nếu bạn muốn một mảng là xác định định dạng byte có một mảng và đó là những công cụ thích xargs
và find
làm: Nếu bạn chạy chúng với -0
đối số, chúng hoạt động theo định dạng mảng nhị phân chấm dứt các phần tử với byte rỗng, thêm ngữ nghĩa vào luồng byte mờ khác.
Thật không may, bash
không thể được cấu hình để phân chia chuỗi trên byte null. Cảm ơn /unix//a/110108/17980 đã cho chúng tôi thấy điều đó zsh
có thể.
xargs
Bạn muốn lệnh của bạn chạy một lần, và bạn nói rằng xargs -0 -n 10000
giải quyết vấn đề của bạn. Không, nó đảm bảo rằng nếu bạn có hơn 10000 tham số, lệnh của bạn sẽ chạy nhiều lần.
Nếu bạn muốn làm cho nó hoàn toàn chạy một lần hoặc thất bại, bạn phải cung cấp -x
đối số và -n
đối số lớn hơn -s
đối số (thực sự: đủ lớn để cả một loạt các đối số có độ dài bằng không cộng với tên của lệnh không khớp các -s
kích thước). ( man xargs , xem đoạn trích phía dưới)
Hệ thống tôi hiện đang sử dụng có một ngăn xếp giới hạn trong khoảng 8 triệu, vì vậy đây là giới hạn của tôi:
$ printf '%s\0' -- {1..1302582} | xargs -x0n 2076858 -s 2076858 /bin/true
xargs: argument list too long
$ printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true
(no output)
bash
Nếu bạn không muốn liên quan đến một lệnh bên ngoài, vòng lặp while-đọc cung cấp một mảng, như được hiển thị trong /unix//a/110108/17980 , là cách duy nhất để bash phân chia mọi thứ tại byte rỗng.
Ý tưởng tìm nguồn script ( . ... "$@" )
để tránh giới hạn kích thước ngăn xếp là tuyệt vời (tôi đã thử nó, nó hoạt động!), Nhưng có lẽ không quan trọng đối với các tình huống thông thường.
Sử dụng một fd đặc biệt cho ống quy trình rất quan trọng nếu bạn muốn đọc một cái gì đó khác từ stdin, nhưng nếu không thì bạn sẽ không cần nó.
Vì vậy, cách "bản địa" đơn giản nhất, cho nhu cầu hàng ngày của gia đình:
files=()
while IFS= read -rd '' file; do
files+=("$file")
done <(find ... -print0)
myscriptornonscript "${files[@]}"
Nếu bạn thích cây quy trình của bạn sạch sẽ và đẹp mắt, phương pháp này cho phép bạn thực hiện exec mynonscript "${files[@]}"
, loại bỏ quá trình bash khỏi bộ nhớ, thay thế nó bằng lệnh được gọi. xargs
sẽ luôn ở trong bộ nhớ trong khi lệnh được gọi chạy, ngay cả khi lệnh chỉ chạy một lần.
Những gì nói chống lại phương pháp bash bản địa là thế này:
$ time { printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true; }
real 0m2.014s
user 0m2.008s
sys 0m0.172s
$ time {
args=()
while IFS= read -rd '' arg; do
args+=( "$arg" )
done < <(printf '%s\0' -- $(echo {1..1302581}))
/bin/true "${args[@]}"
}
bash: /bin/true: Argument list too long
real 107m51.876s
user 107m38.532s
sys 0m7.940s
bash không được tối ưu hóa để xử lý mảng.
người đàn ông xargs :
-n max-args
Sử dụng tối đa các đối số max-args trên mỗi dòng lệnh. Ít hơn các đối số max-args sẽ được sử dụng nếu kích thước (xem tùy chọn -s) bị vượt quá, trừ khi tùy chọn -x được đưa ra, trong trường hợp đó xargs sẽ thoát.
-s ký tự tối đa
Sử dụng tối đa các ký tự ký tự tối đa trên mỗi dòng lệnh, bao gồm lệnh và đối số ban đầu và các kết thúc null ở cuối chuỗi đối số. Giá trị được phép lớn nhất phụ thuộc vào hệ thống và được tính là giới hạn độ dài đối số cho exec, trừ kích thước môi trường của bạn, ít hơn 2048 byte khoảng không. Nếu giá trị này lớn hơn 128KiB, 128Kib được sử dụng làm giá trị mặc định; mặt khác, giá trị mặc định là tối đa. 1KiB là 1024 byte.
-x
Thoát nếu kích thước (xem tùy chọn -s) bị vượt quá.
IFS="
, dòng mới,"
). Nhưng có cần phải thực thi kịch bản trên tất cả các tên tệp không? Nếu không, hãy cân nhắc việc sử dụng find chính nó để thực thi tập lệnh cho mỗi tệp.