Como posso lidar com espaços nos nomes de arquivos ao usar xargs na localização de resultados?

28

Uma das minhas práticas comuns é executar greps em todos os arquivos de um determinado tipo, por exemplo, encontrar todos os arquivos HTML que contenham a palavra "zaragato". Para fazer isso, eu uso

find /path/to -name "*.html" | xargs grep -l "rumpus"

Ocasionalmente, findretornará um arquivo com um espaço em seu nome, como my new file.html. Quando xargspassado isso para grep, no entanto, eu recebo estes erros:

grep: /path/to/bad/file/my: No such file or directory
grep: new: No such file or directory
grep: file.html: No such file or directory

Eu posso ver o que está acontecendo aqui: o pipe ou o xargsestá tratando os espaços como delimitadores entre os arquivos. Pela minha vida, no entanto, não consigo descobrir como evitar esse comportamento. Isso pode ser feito com find+ xargs? Ou tenho que usar um comando totalmente diferente?

abeger
fonte

Respostas:

29

Usar

find ... -print0 | xargs -0 ...

por exemplo

find /path/to -name "*.html"  -print0 | xargs -0  grep -l "rumpus"

na página do manual 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 pro-
          grams that process the find output.  This option  corresponds  to
          the ‘-0’ option of xargs.
user9517 suporta GoFundMonica
fonte
15

Você não precisa usar xargs , porque find pode executar os próprios comandos. Ao fazer isso, você não precisa se preocupar com os caracteres de interpretação do shell no nome.

find /path/to -name "*.html" -exec grep -l "rumpus" '{}' +

na página do manual find

comando -exec {} +
Essa variante da ação -exec executa o comando especificado nos arquivos selecionados, mas a linha de comando é criada anexando cada nome de arquivo selecionado no final; o número total de invocações do comando será muito menor que o número de arquivos correspondentes. A linha de comando é construída da mesma maneira que o xargs cria suas linhas de comando. Apenas uma instância de `{} 'é permitida dentro do comando. O comando é executado no diretório inicial.

sciurus
fonte
Gostaria de aprovar isso, mas ainda não saí hoje - farei amanhã.
user9517 suporta GoFundMonica
11
@ Iain - lá vai você (eu concordo, a propósito).
Eduardo Ivanec
Ao usar o find, você ainda perde os recursos do xargs, além de ter que lidar com regras de cotações tolas. Consulte o argumento -P para xargs se você tiver mais de um núcleo / CPU.
Slartibartfast
8

Se as versões find e xarg em seu sistema não suportarem -print0e -0alternar (por exemplo, AIX find e xargs), você poderá usar isso:

find /your/path -name "*.html" | sed 's/ /\\ /g' | xargs grep -l "rumpus"

Aqui o sed cuidará de escapar dos espaços para xargs.

Jan Ptáčník
fonte
Isso me ajudou porque eu tinha uma longa lista de nomes de arquivos difíceis de produzir que usei várias vezes. Não posso simplesmente ir findtodos novamente.
Scott M.