
Resumindo, quero usar diretórios listados por um comando em um find
comando:
find $(produces_dir_names --options...) -find-options...
O problema vem com espaços em branco nos nomes dos diretórios. Achei que citá-los na saída do comando de produção (que posso alterar) seria suficiente:
"a" "a b" "a b c"
mas bash reclama:
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
Como você pode ver, bash
dividirá a saída do comando em espaços, mesmo com aspas. Tentei mexer IFS
e configurá-lo para \n
, mas minha compreensão parece muito limitada para fazê-lo funcionar.
A única solução alternativa que encontrei foi nesta pergunta do Stack Overflow:
substituição do comando bash remover cotação, ou seja, colocar um eval
na frente dele, mas isso parece meio feio.
Minhas perguntas:
Existe uma maneira fácil e como seria escrever essa substituição, sem o eval
?
As citações são mesmo necessárias?
Exemplo (produzindo a mesma saída):
find $(echo '"a" "a b" "a b c"')
Responder1
Talvez em duas linhas
IFS=$'\n' DIRS=( $(produces_dir_names --options...) )
find "${DIRS[@]}" -find-options...
Exemplo:
$ 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
Mas em geral este não é um bom estilo. Por exemplo, você terá problemas se o seu DIRS contiver novas linhas. Melhor corrigir seu "produces_dir_names" para imprimir strings terminadas em bytes nulos. Em relação ao meu exemplo, isso seria algo como:
$ 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
Se você não consegue corrigir "produces_dir_names", em relação ao meu último comentário, a solução mais geral seria assim:
produces_dir_names --options... | tr '\n' '\0' | xargs -0 -I '{}' find '{}' -find-options...
Ainda problemas com "novas linhas", a menos que você corrija "produces_dir_names" para evitar arquivos tr
.
Responder2
resposta de Rudimeieré bom - especificamente, a parte sobre a modificação produces_dir_names
para imprimir strings terminadas em nulo - mas pode não ser óbvio pela resposta que ele é executado find
uma vez para cada diretório. Se isso for bom o suficiente, tudo bem. Mas, claro, é possível invocar find
com múltiplos pontos de partida; por exemplo,
encontrar diretório 1 diretório 2 diretório 3 -opções de localização...
e parece que é isso que você quer. Isso pode ser feito da seguinte forma:
printf "a\0a b\0a b c" | xargs -0 sh -c 'encontrar "$@" -opções de localização...'sh
Isso faz com xargs
que seja invocado sh -c
uma vez, com todos os nomes de diretório anexados ao comando. O shell será então expandido "$@"
para uma lista desses nomes de diretório.
PS Se produces_dir_names
listar muitos nomes de diretório para colocar em uma linha de comando, xargs
será forçado a gerar alguns comandos. Use xargs --verbose
para ver quais comandos xargs
estão sendo gerados.
Responder3
Apenas para esclarecer o mistério das mensagens de erro que você está recebendo:
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
A resposta é queA remoção de cotações do Bash não remove aspas queresultouda substituição de comando.
DeLESS='+/^ *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.
As "expansões anteriores" mencionadas incluem:
EXPANSION Brace Expansion Tilde Expansion Parameter Expansion Command Substitution Arithmetic Expansion Process Substitution Word Splitting Pathname Expansion Quote Removal