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