Сначала отрежьте тривиальные, но неприменимые ответы: я не могу использовать ни трюк 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). Но это работает!