По- перше , щоб відрізати тривіальних , але непридатних відповідей: Я можу використовувати ні 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). Але це працює!