
Короче говоря, я хочу использовать каталоги, перечисленные командой в find
команде:
find $(produces_dir_names --options...) -find-options...
Проблема в пробелах в именах каталогов. Я думал, что достаточно будет заключить их в кавычки в выводе команды produce (который я могу изменить):
"a" "a b" "a b c"
но bash жалуется:
find: ‘"a"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b’: No such file or directory
find: ‘c"’: No such file or directory
Как вы можете видеть, see bash
разделит вывод команды по пробелам, даже с кавычками. Я пытался поиграться с ним IFS
и установить его на \n
, но мое понимание этого кажется слишком ограниченным, чтобы заставить это работать.
Единственное решение, которое я нашел, было в этом вопросе на Stack Overflow:
замена команды bash удалить кавычки, а именно поставить eval
перед ним , но это выглядит как-то некрасиво.
Мои вопросы:
Есть ли простой способ и как будет выглядеть запись этой замены без eval
?
Нужны ли вообще цитаты?
Пример (производящий тот же результат):
find $(echo '"a" "a b" "a b c"')
решение1
Может быть, в две строки
IFS=$'\n' DIRS=( $(produces_dir_names --options...) )
find "${DIRS[@]}" -find-options...
Пример:
$ mkdir -p "/tmp/test/a b/foo" "/tmp/test/x y/bar"
$ IFS=$'\n' DIRS=( $(printf "/tmp/test/a b\n/tmp/test/x y\n") )
$ find "${DIRS[@]}" -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar
Но в целом это нехороший стиль. Например, у вас будут проблемы, если ваши DIRS содержат новые строки. Лучше исправить ваш "produces_dir_names" для вывода строк с нулевым байтом в конце. Что касается моего примера, то это будет что-то вроде:
$ printf "/tmp/test/a b\0/tmp/test/x y\0" | xargs -0 -I '{}' find '{}' -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar
Если вы не можете исправить «produces_dir_names», то, учитывая мой последний комментарий, наиболее общее решение будет выглядеть так:
produces_dir_names --options... | tr '\n' '\0' | xargs -0 -I '{}' find '{}' -find-options...
Все еще остаются проблемы с «новыми строками», если только вы не исправите «produces_dir_names», чтобы избежать tr
.
решение2
ответ рудимейерахорошо — в частности, часть о модификации produces_dir_names
для печати строк с нулевым завершением — но из его ответа может быть не очевидно, что он выполняется find
один раз для каждого каталога. Если это достаточно хорошо, то отлично. Но, конечно, можно вызывать find
с несколькими начальными точками; например,
находить реж. 1 реж . 2 реж . 3 -варианты поиска...
и из вопроса следует, что это то, что вы хотите. Это можно сделать следующим образом:
printf "a\0a b\0a b c" | xargs -0 sh -c 'найти "$@" -варианты поиска...' ш
Это приводит xargs
к вызову sh -c
один раз, со всеми именами каталогов, добавленными к команде. Затем оболочка расширится "$@"
до списка этих имен каталогов.
PS Если produces_dir_names
выводит слишком много имен каталогов для одной командной строки, то xargs
будет вынуждено порождать несколько команд. Используйте xargs --verbose
для просмотра того, какие команды xargs
порождаются.
решение3
Чтобы прояснить тайну сообщений об ошибках, которые вы получаете:
find: ‘"a"’: No such file or directory find: ‘"a’: No such file or directory find: ‘b"’: No such file or directory find: ‘"a’: No such file or directory find: ‘b’: No such file or directory find: ‘c"’: No such file or directory
Ответ таков:Удаление кавычек в Bash не удаляет кавычки, которыев результатеот замены команд.
ОтLESS='+/^ *Quote Removal' man bash
Quote Removal After the preceding expansions, all unquoted occurrences of the charac- ters \, ', and " that did not result from one of the above expansions are removed.
Упомянутые «предыдущие расширения» включают в себя:
EXPANSION Brace Expansion Tilde Expansion Parameter Expansion Command Substitution Arithmetic Expansion Process Substitution Word Splitting Pathname Expansion Quote Removal