Bash: кавычки в подстановке команд

Bash: кавычки в подстановке команд

Короче говоря, я хочу использовать каталоги, перечисленные командой в 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

Связанный контент