A situação é que eu tenho um MP3 player mpg321
que aceita uma lista de arquivos como argumento. Eu mantenho minha música em um diretório chamado "music", no qual existem mais alguns diretórios. Eu só quero jogar todos eles, então eu corro o programa com
mpg321 $(find /music -iname "*\.mp3")
. O problema é que alguns nomes de arquivos têm espaços em branco, e o programa divide esses nomes em partes menores e reclama de arquivos ausentes. Agrupando o resultado entre find
aspas
mpg321 "$(find /music -iname "*\.mp3")"
não ajuda porque tudo se tornará um "nome de arquivo" grande, o que obviamente não foi encontrado.
Como posso fazer isso então? Se isso importa, estou usando bash
, mas mudarei para zsh
breve.
fonte
mpg321 $(find /music -iname "*\.mp3" -print0)
que não?mpg321
não tem nada a ver com isso, é o shell que está dividindo a saídafind
em argumentos separados. E-print0 | xargs -0
funcionará com todos os nomes de arquivos possíveis.Com o GNU find, você também pode usar
-print0
exargs -0
, mas há pouco sentido em aprender mais uma ferramenta. A-exec ... {} +
sintaxe recebe pouca menção porque o Linux a adquiriu posteriormente-print0
, mas não há razão para não usá-lo agora.Com zsh ou bash 4, isso é muito mais simples:
Somente no zsh, você pode fazer um (parte de a) sem distinção entre maiúsculas e minúsculas:
fonte
Acho que a solução de Steven é a melhor, mas outra maneira é usar o
-I
sinalizador de xargs , que permite especificar uma string que será substituída no comando pelo argumento (em vez de apenas anexar o argumento ao final do comando). Você pode usar isso para citar o argumento:fonte
-0
sinalizador de xargs sem encontrar-print0
. Além disso, a-I
bandeira de xargs tem várias consequências. Ao contrário do simples,xargs
que comprimirá todas as linhas de stdin em um comando,xargs -I
será executadompg321
potencialmente centenas ou milhares de vezes (uma vez para cada arquivo), o que certamente não é a intenção. Lembre-se também de que citar foo é desnecessário, assim comoxargs
isso internamente. Observe que se você compactar todos os nomes de arquivos na linha de linha e enviá-los paraxargs -I
, eles não serão abertos.Geralmente, é melhor diretamente,
-exec ${tgt_process} \{\} +
mas se você precisar obter uma lista de nomes de arquivos delimitada de maneira confiável e confiável em um arquivo ou fluxo,find
por qualquer motivo, poderá fazer o seguinte:O que você obtém disso são duas seqüências únicas . No início de cada nome de arquivo está a string
\n///
e na cauda de todo nome de arquivo está a string///\n
. Essas duas seqüências de caracteres não ocorrem em nenhum outro lugar nafind
saída de, exceto nessas posições, independentemente dos caracteres que os nomes de arquivos contêm.Além disso, o uso acima é portátil POSIX básico e pode ser utilizado para trabalhar em praticamente qualquer sistema unix. Isso não se aplica ao uso de um delimitador de byte nulo - apesar de sua conveniência - recomendado por alguns outros.
Mas, novamente, isso só é necessário se você não puder diretamente o
-exec
seu$tgt_process
por qualquer motivo, pois esse deve ser seu objetivo. Por um lado, o método acima ainda requer análise. Por exemplo, se você quisesse cada shell de nome de arquivo citado, primeiro teria que garantir que quaisquer aspas no nome do arquivo fossem escapadas:Isso gera uma matriz de nomes de arquivos com escape apropriado, independentemente de quais sejam seus caracteres constituintes. Agora você só precisa esperar que seu aplicativo no lado receptor não o altere.
fonte
Outra maneira de fazer isso é escapar de todos os caracteres especiais que aparecem nos nomes dos arquivos. Por exemplo:
Basicamente, isso passará os nomes de arquivos com escape adequado para xargs para execução e não haverá problemas.
fonte
sed 's|.|\\&|g'
- é o que o POSIX recomenda de qualquer maneira.