Como eu procuro uma string em um grupo de arquivos quando alguns desses arquivos contêm espaços?

2

Estou executando o Mac 10.7.5. Em um terminal, usarei este comando para localizar arquivos com strings

find src/main -name "*" | xargs grep -i 'mystring'

No entanto, quando os arquivos contêm espaços, recebo resultados como

grep: images/mystuff/essential-questions-selected-arrow-ela: No such file or directory
grep: 5.24.38: No such file or directory
grep: PM.png: No such file or directory

O arquivo atual no exemplo acima é "essential-questions-selected-arrow-ela" 5.24.38 PM.png "Como executo o comando acima com sucesso, mesmo se os arquivos que estão sendo pesquisados contiverem espaços?

    
por Dave A 19.12.2013 / 22:20

2 respostas

4

Se você quiser usar find output em xargs , a maneira recomendada é canalizá-lo usando NUL caracteres para delimitar cada nome de arquivo:

find src/main -name "*" -print0 | xargs -0 grep -i 'mystring'

A razão para isso é que o shell (e xargs especificamente) geralmente divide argumentos (ou insira no caso de xargs ) com base no espaço em branco, ou seja, espaços, tabulações e novas linhas. Depois de usar -0 , xargs lerá cada campo separado por NUL , que é o que find -print0 produz.

Isso funcionará no GNU find e xargs , bem como nas versões incluídas no OS X. Outras versões podem não ter as opções, pois elas não são necessárias no POSIX.

Mas, novamente, isso não é realmente necessário. O padrão de nome "*" se expande para todos os nomes possíveis. grep pode reciclar sozinho, então tudo que é necessário é:

grep -ri 'mystring' src/main

No Bash 4 (não fornecido com o OS X por padrão), você também pode fazer globalização recursiva, por exemplo sobre todos os arquivos .txt , usando a opção globstar :

shopt -s globstar
grep -i 'mystring' **/*.txt
    
por 19.12.2013 / 22:24
2

De longe, a maneira mais segura e fácil de fazer esse tipo de coisa é usar a opção -exec do find. De man find :

-exec utility [argument ...] ;
     True if the program named utility returns a zero value as its exit status.
     Optional arguments may be passed to the utility.  The expression must be 
     terminated by a semicolon ('';'').  If you invoke find from a shell you 
     may need to quote the semicolon if the shell would otherwise treat it as a 
     control operator.  If the string ''{}'' appears anywhere in the utility 
     name or the arguments it is replaced by the pathname of the current file.  
     Utility will be executed from the directory from which find was executed.  
     Utility and arguments are not subject to the further expansion of shell 
     patterns and constructs.

-exec utility [argument ...] {} +
     Same as -exec, except that ''{}'' is replaced with as many pathnames as 
     possible for each invo-cation invocationcation of utility. This behaviour 
     is similar to that of xargs(1).

Em outras palavras, a opção -exec executará o que você der nos resultados de find, substituindo {} por cada arquivo (ou diretório) encontrado. Então, para grep para uma string específica, você faria:

find src/main -name "*" -exec grep -i 'mystring' {} +

Isso, no entanto, também encontrará diretórios e dará um erro. Ele vai funcionar, lembre-se, ele só vai reclamar quando você tentar executá-lo em um diretório, você teria o mesmo problema usando xargs . O que você está realmente tentando fazer aqui é encontrar todos os arquivos e apenas arquivos. Nesse caso, o -name '*' não é necessário, pois find src/main é exatamente igual a find src/main -name "*" . Então, ao invés de usar isso, especifique que você só quer encontrar arquivos:

find src/main -type f -exec grep -i 'mystring' {} +
    
por 19.12.2013 / 22:49