Primeiro, para interromper respostas triviais, mas inaplicáveis: não posso usar nem o truque find
+ xargs
nem suas variantes (como find
com -exec
) porque preciso usar poucas dessas expressões por chamada. Eu voltarei a isso no final.
Agora, para um melhor exemplo, vamos considerar:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Como faço para passar esses argumentos para program
?
Apenas fazendo isso não faz o truque
$ ./program $(find -L some/dir -name \*.abc | sort)
falha porque program
recebe 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.
Citar até que funcione
Parece que usuários iniciantes como eu, quando se deparam com esses problemas, tendem a adicionar citações aleatoriamente até que finalmente funcione - somente aqui isso 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. Então, não só não impediram a divisão de palavras, mas também entraram em discussões!
Alterar o IFS
Então eu tentei brincar com IFS
. Eu preferiria find
com -print0
e sort
com -z
de qualquer forma - para que eles mesmos não tivessem problemas com "caminhos com fio". Então, por que não forçar a divisão de palavras no caractere null
e ter tudo isso?
$ ./program $(IFS=$'$ 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
' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Por isso, ele ainda se divide no espaço e não é dividido em null
.
Eu tentei colocar a atribuição IFS
em $(…)
(como mostrado acima) e antes de ./program
. Também tentei outras sintaxes como \x0
, \x00
, '
, ambas citadas com "
e $
, bem como com e sem program
. Nada disso pareceu fazer diferença…
E aqui estou sem ideias. Tentei mais algumas coisas, mas todas pareciam ter os mesmos problemas listados.
O que mais eu poderia fazer? É factível?
Claro, consegui que grep
aceitasse os padrões e fizesse buscas em si. Mas é muito trabalho duplo enquanto o corrige para uma sintaxe específica. (Que tal fornecer arquivos por um program
, por exemplo?).
Além disso, consegui que find
aceitasse um arquivo com uma lista de caminhos. Então, posso facilmente copiar find
expressão para algum arquivo temporário e fornecer o caminho para esse arquivo apenas. Isso poderia ser suportado por caminhos diretos para que, se o usuário tivesse apenas um caminho simples, ele pudesse ser fornecido sem o arquivo intermediário. Mas isso não parece bom - é necessário criar arquivos extras e cuidar deles, sem mencionar a implementação extra necessária. (No lado positivo, no entanto, pode ser um resgate para casos em que o número de arquivos como argumentos começa a causar problemas com o tamanho da linha de comando ...)
No final, deixe-me lembrá-lo de que os truques xargs
+ xargs
(e similares) não funcionarão no meu caso. Para simplicidade de descrição, estou mostrando apenas um argumento. Mas meu verdadeiro caso parece mais com isso:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Portanto, fazer um %code% de uma pesquisa ainda me deixa como lidar com a outra…