Como executo o xargs grep na saída do grep que possui espaços?

8

Estou pesquisando arquivos com base em uma expressão regular e, em seguida, estou tentando pesquisar nesses arquivos por conteúdo. Então, por exemplo, eu tenho algo parecido com

#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp" | grep "<name regex>" | xargs grep "<content regex>"

O problema que estou correndo é que alguns dos caminhos têm espaços neles, o que confunde xargs . Eu sei que se eu estivesse usando apenas find , eu poderia usar o argumento -print0 (junto com o argumento -0 em xargs ) para evitar que os xargs tratassem os espaços como delimitadores. Existe algo semelhante com grep ?

Ou estou abordando esse problema de maneira totalmente errada? Ingenuamente, find to grep to xargs grep faz sentido para mim, mas estou aberto a outras abordagens que produzem os mesmos resultados.

    
por quanticle 19.03.2015 / 19:15

4 respostas

5

Use algo como isto talvez (se gnu grep).

grep -r 'content pattern' --include==*.cpp

homem grep

--include=GLOB Search only files whose base name matches GLOB (using wildcard matching as described under --exclude)

Veja também as opções para delimitadores nulos.

-Z, --null Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name. For example, grep -lZ outputs a zero byte after each file name instead of the usual newline. This option makes the output unambiguous, even in the presence of file names containing unusual characters like newlines. This option can be used with commands like find -print0, perl -0, sort -z, and xargs -0 to process arbitrary file names, even those that contain newline characters.

-z, --null-data Treat the input as a set of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline. Like the -Z or --null option, this option can be used with commands like sort -z to process arbitrary file names.

    
por 19.03.2015 / 19:37
4

Se você tiver que passar por muitos obstáculos, a eficiência dos xargs será perdida de qualquer maneira. Aqui está um trabalho bruto:

find . -iname "*.cpp" | grep "<pattern>" | while read -r x; do grep exa "$x"; done

Sempre que tenho problemas com espaços em nomes de arquivos, a resposta é aspas duplas em uma variável.

    
por 19.03.2015 / 20:17
3

Use find para fazer toda a filtragem de nome de arquivo. Em vez de

find . -name "*.cpp" | grep "foo" | xargs grep …

fazer

find . -name "*.cpp" -name "*foo*" -print0 | xargs -0 grep …

Se você quiser fazer algo um pouco mais complicado, como

find . -name "*.cpp" | egrep "foo|bar" | xargs grep …

você pode fazer

find . -name "*.cpp" "(" -name "*foo*" -o -name "*bar*" ")" -print0 | xargs -0 grep …

Observe que isso deve funcionar mesmo para arquivos com novas linhas em seus nomes.

E, se você precisar do poder de expressões regulares completas, você pode usar -regex .

    
por 20.03.2015 / 05:31
3

Isso deve funcionar mesmo sem as ferramentas do GNU:

#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp"  | grep "<name regex>" | perl -pe 's/\n/
#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp"  | grep "<name regex>" | perl -pe 's/\n/%pre%/' \
  | xargs -0 grep "<content regex>"
/' \ | xargs -0 grep "<content regex>"

A chamada perl substitui as quebras de linha por caracteres nulos, o que permitirá que xargs -0 interprete a entrada em uma base por linha em vez de usar uma base por espaço em branco.

Usando o GNU, você pode remover a chamada perl e alterar xargs -0 … para xargs -d "\n" …

Não tem perl ou GNU? Experimente awk '{printf "%s%c", $0, 0}' .

    
por 19.03.2015 / 19:50