По- перше , щоб відрізати тривіальних , але непридатних відповідей: Я можу використовувати ні find
+ xargs
трюк , ні його варіанти (наприклад , find
з -exec
) , тому що мені потрібно використовувати кілька таких виразів на виклик. Я повернусь до цього наприкінці.
Тепер для кращого прикладу розглянемо:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Як я можу передати це як аргументи program
?
Тільки робити це не вийде
$ ./program $(find -L some/dir -name \*.abc | sort)
не вдається, оскільки program
отримує такі аргументи:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Як видно, шлях з простором був розділений і program
вважає це двома різними аргументами.
Цитуйте, поки це не працює
Здається, початківці користувачі, такі як я, стикаються з такими проблемами, як правило, випадковим чином додають котирування, поки нарешті це не спрацює - тільки тут, здається, це не допоможе ...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Оскільки лапки запобігають поділу слів, всі файли передаються як єдиний аргумент.
Цитуючи окремі шляхи
Перспективний підхід:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
Цитати там, звичайно. Але вони вже не інтерпретуються. Вони просто частина струн. Тож не тільки вони не завадили розколоти слова, але й вони вступили в аргументи!
Змінити IFS
Потім я спробував пограти з IFS
. Я волів би find
з -print0
і sort
з -z
так чи інакше - так , що у них не буде ніяких проблем на «прописані шляхи» самі. То чому б не змусити розбивати слова на null
персонажа і мати все це?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Таким чином, він все ще розпадається на простір і не розщеплюється на null
.
Я намагався розмістити IFS
завдання як у $(…)
(як показано вище), так і раніше ./program
. Також я спробував інший синтаксис , як \0
, \x0
, \x00
і цитував з '
і "
в тому числі без $
. Ніхто з них не мав жодного значення ...
І ось у мене ідеї. Я спробував ще кілька речей, але все, здавалося, стикався з тими ж проблемами, що перераховані.
Що я ще міг зробити? Це взагалі можливо?
Звичайно, я міг би змусити program
приймати шаблони і робити сам пошук. Але це багато подвійної роботи при фіксації її до певного синтаксису. (Що робити із забезпеченням файлів grep
наприклад?).
Також я міг би змусити program
прийняти файл зі списком шляхів. Тоді я можу легко скинути find
вираз у якийсь тимчасовий файл і надати шлях лише до цього файлу. Це може підтримуватися прямими шляхами, так що якщо у користувача є просто простий шлях, його можна надати без проміжного файлу. Але це не здається приємним - потрібно створити додаткові файли та подбати про них, не кажучи вже про необхідність додаткової реалізації. (З позитивного боку, однак, це може бути порятунком для випадків, коли кількість файлів як аргументів починає викликати проблеми з довжиною командного рядка…)
Наприкінці дозвольте ще раз нагадати, що find
+ xargs
(і подібні) трюки у моєму випадку не спрацюють. Для простоти опису я показую лише один аргумент. Але мій справжній випадок виглядає приблизно так:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
Тож xargs
пошук із одного результату все ще залишає мене, як поводитися з іншим ...
mapfile
(або його синоніміreadarray
). Але це працює!