Чи не існує способу захисту пробілів у розширенні backtick (або $ (...))?
Ні, немає. Чому так?
Баш не може знати, що слід захищати, а що не слід.
У файлі / трубі unix немає масивів. Це просто потік байтів. Команда всередині ``
або $()
виводить потік, який bash проковтує і розглядає як єдиний рядок. З цього моменту у вас є лише два варіанти: помістити його в лапки, зберегти його як один рядок або поставити його оголеним, щоб баш розбив його відповідно до налаштованої поведінки.
Тож, що вам потрібно зробити, якщо ви хочете масив, - це визначити формат байтів, який має масив, і це те, що інструменти люблять xargs
і find
роблять: якщо ви запускаєте їх з -0
аргументом, вони працюють у форматі бінарного масиву, який завершує елементи з нульовий байт, додаючи семантику до інакше непрозорого потоку байтів.
На жаль, bash
не може бути налаштовано на розділення рядків на нульовий байт. Дякуємо /unix//a/110108/17980 за те, що показали нам, що zsh
можемо.
xargs
Ви хочете, щоб ваша команда була запущена один раз, і ви сказали, що це xargs -0 -n 10000
вирішує вашу проблему. Це не так, це гарантує, що якщо у вас більше 10000 параметрів, ваша команда буде виконуватись більше одного разу.
Якщо ви хочете зробити це строго або запустити один раз, або не виконати помилку, ви повинні навести -x
аргумент і -n
аргумент, більший за -s
аргумент (дійсно: досить великий, що ціла купа аргументів нульової довжини плюс назва команди не вміщуються в -s
розмір). ( людина xargs , див. уривок далеко нижче)
Система, на якій я зараз перебуваю, має стек, обмежений приблизно 8М, тому ось мій ліміт:
$ 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)
баш
Якщо ви не хочете залучати зовнішню команду, цикл під час читання, що подає масив, як показано на /unix//a/110108/17980 , є єдиним способом для bash розділити речі на нульовий байт.
Ідея джерела сценарію ( . ... "$@" )
щоб уникнути обмеження розміру стека, класна (я спробував це, він працює!), Але, ймовірно, не важливий для нормальних ситуацій.
Використання спеціального fd для технологічної труби важливо, якщо ви хочете прочитати щось інше зі stdin, але в іншому випадку вам це не знадобиться.
Отже, найпростіший "рідний" спосіб для повсякденних побутових потреб:
files=()
while IFS= read -rd '' file; do
files+=("$file")
done <(find ... -print0)
myscriptornonscript "${files[@]}"
Якщо вам подобається, що ваше дерево процесів є чистим і приємним для перегляду, цей метод дозволяє зробити це exec mynonscript "${files[@]}"
, який видаляє процес bash з пам'яті, замінюючи його на викликану команду. xargs
завжди залишатиметься в пам'яті, поки запускається викликана команда, навіть якщо команда буде виконуватися лише один раз.
Що говорить проти рідного методу bash:
$ 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 не оптимізований для обробки масиву.
man xargs :
-n max-args
Використовуйте не більше аргументів max-args у командному рядку. Менше, ніж аргументи max-args будуть використані, якщо розмір (див. Опцію -s) буде перевищено, якщо не вказано опцію -x, у цьому випадку xargs вийде.
-s max-chars
Використовуйте не більше max-chars символів у командному рядку, включаючи команду та початкові аргументи та завершальні нулі на кінцях рядків аргументів. Найбільше дозволене значення залежить від системи і обчислюється як обмеження довжини аргументу для exec, за винятком розміру вашого середовища, менше 2048 байтів прогону. Якщо це значення перевищує 128KiB, то за замовчуванням використовується 128Kib; в іншому випадку значення за замовчуванням є максимальним. 1KiB - 1024 байти.
-х
Вийдіть, якщо розмір (див. Опцію -s) перевищено.
IFS="
новий рядок"
). Але чи потрібно виконувати сценарій над усіма іменами файлів? Якщо ні, подумайте про те, щоб знайти себе для виконання сценарію для кожного файлу.