O que faz o “xargs grep”?

15

Eu sei o comando grep e estou aprendendo sobre as funcionalidades de xargs , então eu li através de esta página que fornece alguns exemplos sobre como usar o comando xargs .

Estou confuso com o último exemplo, exemplo 10. Ele diz "O comando xargs executa o comando grep para localizar todos os arquivos (entre os arquivos fornecidos pelo comando find) que continham uma string 'stdlib.h'"

$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...

No entanto, qual é a diferença para simplesmente usar

$ find . -name '*.c' | grep 'stdlib.h'

?

Obviamente, ainda estou lutando com o que exatamente xargs está fazendo, então qualquer ajuda é apreciada!

    
por AlphaOmega 04.10.2016 / 23:50

4 respostas

21
$ find . -name '*.c' | grep 'stdlib.h'

Isso canaliza a saída (stdout) * de find para (stdin of) * grep 'stdlib.h' como texto (ou seja, os nomes dos arquivos são tratados como texto). grep faz o mesmo e encontra as linhas correspondentes neste texto (qualquer nome de arquivo que contenha o padrão). O conteúdo dos arquivos nunca é lido.

$ find . -name '*.c' | xargs grep 'stdlib.h'

Isso cria um comando grep 'stdlib.h' para o qual cada resultado de find é um argumento - portanto, ele procurará correspondências dentro de cada arquivo encontrado por find ( xargs pode ser considerado como transformando seu stdin em argumentos para os comandos fornecidos) *

Use -type f no seu comando find ou você obterá erros de grep para os diretórios correspondentes. Além disso, se os nomes dos arquivos tiverem espaços, xargs será muito ruim, portanto, use o separador nulo adicionando -print0 e xargs -0 para obter resultados mais confiáveis:

find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

* adicionou esses pontos extras explicativos como sugerido no comentário de @cat

    
por Zanna 05.10.2016 / 00:04
4

O xargs usa sua entrada padrão e a transforma em argumentos da linha de comando.

find . -name '*.c' | xargs grep 'stdlib.h' é muito semelhante a

grep 'stdlib.h' $(find . -name '*.c')  # UNSAFE, DON'T USE

E fornecerá os mesmos resultados, desde que a lista de nomes de arquivos não seja muito longa para uma única linha de comando. (Linux suporta megabytes de texto em uma única linha de comando, então normalmente você não precisa de xargs.)

Mas ambos são ruins, porque quebram se seus nomes de arquivos contiverem espaços . Em vez disso, find -print0 | xargs -0 funciona, mas o mesmo acontece

find . -name '*.c' -exec grep 'stdlib.h' {} +

Isso nunca canaliza os nomes dos arquivos em qualquer lugar: find os coloca em uma grande linha de comando e executa grep diretamente.

\; em vez de + executa grep separadamente para cada arquivo, o que é muito mais lento. Não faça isso. Mas + é uma extensão GNU, então você precisa de xargs para fazer isso de forma eficiente se você não puder assumir o GNU.

Se você deixar de fora xargs , find | grep fará a correspondência de padrões com a lista de nomes de arquivos que find imprime.

Então, nesse ponto, você também pode fazer find -name stdlib.h . É claro que, com -name '*.c' -name stdlib.h , você não obterá nenhuma saída porque esses padrões não podem ser iguais, e o comportamento padrão de encontrar é AND as regras juntas.

Substitua less em qualquer ponto no processo para ver qual saída qualquer parte do pipeline produz.

Outras leituras: link tem ótimas coisas.

    
por Peter Cordes 05.10.2016 / 04:16
3

Em geral, xargs é usado para casos em que você canalizaria (com o símbolo | ) algo de um comando para outro ( Command1 | Command2 ), mas a saída do primeiro comando não é recebida corretamente como a entrada para o segundo comando.

Isso geralmente acontece quando o segundo comando não manipula corretamente a entrada de dados por meio da entrada padrão (stdin) (por exemplo: várias linhas como entrada, como as linhas são configuradas, os caracteres usados como entrada, vários parâmetros como entrada, tipo recebido como entrada, etc ..). Para lhe dar um exemplo rápido, teste o seguinte:

Exemplo 1:

ls | echo - Isso não fará nada, pois echo não sabe como manipular a entrada que está recebendo. Agora, neste caso, se usarmos xargs , ele processará a entrada de uma maneira que possa ser manipulada corretamente por echo (por exemplo: Como uma única linha de informação)

ls | xargs echo - Isso gerará todas as informações de ls em uma única linha

Exemplo 2:

Digamos que eu tenha vários arquivos goLang dentro de uma pasta chamada go. Eu procuraria por eles com algo assim:

find go -name *.go -type f | echo - Mas se o símbolo de pipe e o echo no final, não funcionaria.

find go -name *.go -type f | xargs echo - Aqui funcionaria graças a xargs , mas se eu quisesse cada resposta do comando find em uma única linha, faria o seguinte:

find go -name *.go -type f | xargs -0 echo - Nesse caso, a mesma saída de find seria mostrada por echo .

Comandos como cp, echo, rm, less e outros que precisam de uma maneira melhor de manipular a entrada obtêm um benefício quando usados com xargs .

    
por Luis Alvarado 05.10.2016 / 00:21
0

xargs é usado para gerar automaticamente argumentos de linha de comando baseados (geralmente) em uma lista de arquivos.

Existem várias razões para usá-lo que ainda não vejo mencionadas acima:

  1. find . -name '*.c' -exec grep {}\; gerará um grep do processo para cada arquivo - isso geralmente é considerado uma má prática e pode colocar uma grande carga no sistema se houver muitos arquivos encontrados.
  2. Se houver muitos arquivos, um comando grep 'stdlib.h' $(find . -name '*.c') provavelmente falhará, porque a saída da operação $(...) excederá o comprimento máximo da linha de comando do shell

Como mencionado acima, geralmente é boa prática usar o argumento -print0 para find neste cenário e o argumento -0 para xargs, para que nomes de arquivos com determinados caracteres (por exemplo, citações ou espaços) ainda sejam manipulados corretamente.

    
por Michael Firth 05.10.2016 / 11:52