como passar o resultado de 'find' como uma lista de arquivos?

9

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. Envolvendo o resultado de find entre aspas

mpg321 "$(find /music -iname "*\.mp3")"

não ajuda porque todos se tornarão um grande "nome de arquivo", o que obviamente não é encontrado.

Como posso fazer isso então? Se isso for importante, estou usando bash , mas mudarei para zsh em breve.

    
por phunehehe 01.10.2010 / 18:04

5 respostas

15

Tente usar a opção -print0 ou -printf do find em combinação com xargs da seguinte forma:

find /music -iname "*\.mp3" -print0 | xargs -0 mpg321

Como isso funciona é explicado pela página de manual do find :

-print0

True; print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output. This option corresponds to the -0 option of xargs.

    
por 01.10.2010 / 18:08
7
find /music -iname "*\.mp3" -exec mpg123 {} +

Com o GNU find, você também pode usar -print0 e xargs -0 , mas não faz sentido aprender outra ferramenta. A sintaxe -exec ... {} + é pouco mencionada porque o Linux a adquiriu depois de -print0 , mas não há razão para não usá-la agora.

Com o zsh ou o bash 4, isso é muito mais simples:

mpg123 **/*.[Mm][Pp]3

Somente no zsh, você pode tornar um (parte de um) padrão sem diferenciação de maiúsculas e minúsculas:

mpg123 (#i)**/*.mp3
    
por 01.10.2010 / 20:56
2

Acho que A solução de Steven é a melhor, mas outra maneira é usar xargs ' -I flag, que permite especificar uma string que será substituída no comando pelo argumento (em vez de apenas anexar o argumento em o fim do comando). Você pode usar isso para citar o argumento:

find /music -iname "*\.mp3" | xargs -0 -Ifoo mpg321 "foo"
    
por 01.10.2010 / 19:25
1

Geralmente, é melhor usar diretamente -exec ${tgt_process} \{\} + , mas se precisar obter uma lista de nomes de arquivos confiável e delimitada em um arquivo ou fluxo de find por qualquer motivo, você pode fazer isso :

find -exec sh -c 'printf "///%s///\n" "$@"' -- \{\} +

O que você ganha com isso são duas strings exclusivas . Na cabeça de cada nome de arquivo está a string \n/// e na cauda de cada nome de arquivo está a string ///\n . Essas duas strings não ocorrem em nenhum outro lugar na saída de find , exceto naquelas posições, independentemente de quaisquer caracteres que os nomes de arquivos contenham.

Além disso, o uso acima é portátil POSIX de base e pode ser usado em praticamente qualquer sistema unix. Isso não é verdade para o 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 -exec your $tgt_process por qualquer motivo, já que esse deve ser seu objetivo. Por um lado, o método acima ainda requer análise. Por exemplo, se você quisesse que cada shell do nome do arquivo fosse citado, primeiro teria que garantir que as aspas duras no nome do arquivo fossem escapadas:

find ... + | sed 's|'\''|&"&"&|g;s|///|'\''|g'

Isso gera uma matriz de nomes de arquivos com escape de shell propriamente dita, independentemente de quaisquer que sejam seus caracteres constituintes. Agora você só tem que esperar que seu aplicativo no final de recebimento não o atrapalhe.

    
por 10.06.2014 / 04:56
0

Outra maneira de fazer isso é escapar todos os caracteres especiais que vêm em seus nomes de arquivos. Por exemplo:

find /music -iname "*\.mp3" | sed 's!\([] \*\$\/&[]\)!\!g' | xargs mpg321

Isso basicamente passará os nomes dos arquivos com escape adequado para xargs para execução e não haverá problemas.

    
por 10.06.2014 / 04:02