Erro estranho “No such file” com “xargs” e “file”

5

Gostaria de obter o tipo MIME de todos os arquivos no diretório atual. Por que isso não funciona? Eu testei o bash no OSX ou no Linux. "file" reclama que não pode encontrar o arquivo, mas se eu o executar com o mesmo caminho exato que ele funciona.

$ find . -type f | xargs -n 1 -I FILE echo $(file --mime-type -b FILE)
ERROR: cannot open './foo.txt' (No such file or directory)
...
$ file --mime-type -b ./foo.txt
text/plain

Claro que no mundo real eu não apenas "echo" a resposta, eu preciso usar a string tipo MIME em outro comando.

Este é o mais simples que eu poderia fazer o problema. Eu acho que não estou entendendo algo sobre xargs substituição de nome de arquivo?

    
por jamshid 13.11.2013 / 04:24

3 respostas

5

A substituição do comando $(file --mime-type -b FILE) é executada pelo shell antes de ser passada para xargs , e é por isso que você não está vendo o que precisa. Citar $(file --mime-type -b FILE) e passá-lo para bash -c via xargs

find . -type f | xargs -n 1 -I FILE bash -c  'echo $(file --mime-type -b FILE)'
    
por 13.11.2013 / 04:47
4

Não há necessidade de usar xargs aqui. Basta usar a opção find do -exec .

$ find . -type f -exec file --mime-type -- {} +

Exemplos

padrão file output

$ find 8* -type f -exec file --mime-type -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

file -b output

$ find 8* -type f -exec file --mime-type -b -- {} + | head -5
application/x-empty
text/x-perl
text/plain
text/plain
text/plain

Alternativas

Este é apenas um FYI, mas há outro comando chamado mimetype , que você também pode usar para fazer o mesmo que file --mimetype . Este comando faz parte deste pacote no Fedora, perl-File-MimeInfo , e funciona de forma semelhante:

$ find 8* -type f -exec mimetype -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

Exec mais elaborado

Se você tiver perguntado sobre "fazer mais do que apenas ecoar" e já que está tentando usar xargs , concluo que você está pensando em fazer mais elaborações com xargs .

Mas se você estiver usando find , geralmente esse não é o melhor caminho a seguir. Em vez disso, você pode usar find e, em find , -exec switch, chamar um shell e fazer coisas mais complicadas aqui, em vez de tentar convencer xargs a fazer isso de uma maneira mais complexa.

$ find . -type f -exec sh -c '
   cmd1;
   cmd2;
   file --mime-type -b "$@";
   cmd3;
   cmd4;
 ' sh {} \;

OBSERVAÇÃO: que eu mudei usando o + terminator que passa vários argumentos para file --mime-type ... para \; , que passa um de cada vez.

Exemplo

$ find 8* -type f -exec sh -c '
   echo -n "mime-type: "; 
   file --mime-type -b "$@"
  ' sh {} \; |& tail -10
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/x-shellscript
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
    
por 13.11.2013 / 05:01
3

Seu problema é sobre expansão de shell. $ () é expandido antes de ser entregue como argumento. Se você quiser tratá-lo como está, cite-o e chame um shell para ele.

Além disso, se você processar nomes de arquivos, adquira o hábito de usar print0 e 0, pois deixá-los fora produzirá problemas para você com nomes de arquivos que contêm caracteres de espaço.

Exemplo:

find . -type f -print0 | xargs -0 -n 1 -I FILE bash -c 'echo $(file --mime-type -b FILE)'

No seu caso, isso pode ser simplificado para:

find . -type f -print0 | xargs -0 -n 1 file --mime-type -b

Um comentário adicional: Chamar um programa para todos os arquivos encontrados (seja xargs -n 1 ou find + exec) pode ser um gargalo real no desempenho. Se você tiver um diretório com milhares de arquivos, gerará milhares de processos.

    
por 13.11.2013 / 15:30