Primeiro, para eliminar respostas triviais, mas inaplicáveis: não posso usar o truque find
+ xargs
nem suas variantes (como find
em -exec
) porque preciso usar poucas expressões desse tipo por chamada. Voltarei a isso no final.
Agora, para um exemplo melhor, vamos considerar:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Como passo esses argumentos para program
?
Apenas fazê-lo não faz o truque
$ ./program $(find -L some/dir -name \*.abc | sort)
falha desde que program
obtém os seguintes argumentos:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Como pode ser visto, o caminho com espaço foi dividido e program
considera dois argumentos diferentes.
Cite até que funcione
Parece que usuários iniciantes como eu, quando enfrentamos esses problemas, tendem a adicionar aspas aleatoriamente até que finalmente funcione - só que aqui não parece ajudar…
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Como as aspas impedem a divisão de palavras, todos os arquivos são passados como um único argumento.
Citando caminhos individuais
Uma abordagem promissora:
$ ./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"
As citações estão aí, com certeza. Mas eles não são mais interpretados. Eles são apenas parte das cordas. Portanto, não apenas eles não impediram a divisão de palavras, mas também entraram em discussões!
Alterar IFS
Então eu tentei brincar com IFS
. Eu preferiria find
com -print0
e sort
com -z
qualquer maneira - para que eles não tenham problemas nos "caminhos com fio". Então, por que não forçar a divisão de palavras no null
personagem e ter tudo?
$ ./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
Portanto, ele ainda se divide no espaço e não se divide no null
.
Tentei colocar a IFS
tarefa tanto em $(…)
(como mostrado acima) quanto antes ./program
. Também eu tentei outra sintaxe como \0
, \x0
, \x00
ambos citados com '
e "
, assim como com e sem o $
. Nenhum deles parecia fazer diferença ...
E aqui estou sem idéias. Tentei mais algumas coisas, mas tudo parecia ter os mesmos problemas listados.
O que mais eu poderia fazer? É factível?
Claro, eu poderia program
aceitar os padrões e fazer pesquisas em si. Mas é muito trabalho duplo, enquanto corrige-o para uma sintaxe específica. (Que tal fornecer arquivos com um grep
por exemplo?).
Também eu poderia fazer o program
aceitar um arquivo com uma lista de caminhos. Em seguida, posso despejar facilmente a find
expressão em algum arquivo temporário e fornecer o caminho apenas para esse arquivo. Isso pode ser suportado em caminhos diretos, para que, se o usuário tiver apenas um caminho simples, ele possa ser fornecido sem arquivo intermediário. Mas isso não parece bom - é preciso criar arquivos extras e cuidar deles, sem mencionar a implementação extra necessária. (No lado positivo, no entanto, pode ser um resgate para os casos em que o número de arquivos como argumentos começa a causar problemas com o comprimento da linha de comando ...)
No final, gostaria de lembrá-lo novamente que find
+ xargs
(e similares) truques não funcionarão no meu caso. Para simplificar a descrição, estou mostrando apenas um argumento. Mas meu caso verdadeiro se parece mais com isso:
$ 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
Fazer xargs
uma pesquisa a partir de uma ainda me deixa com como lidar com a outra…
mapfile
(ou seu sinônimoreadarray
). Mas funciona!