Diferença em dois tipos de comando que usa grep

5

Então, aqui temos dois comandos:

cat /var/log/dpkg.log | grep " \install\ "
cat /var/log/dpkg.log | grep install

Por que as saídas desses comandos são diferentes? E você pode por favor explicar o primeiro comando um pouco. Obrigado antecipadamente.

    
por Raphael 21.12.2015 / 17:25

3 respostas

8

A primeira parte de seus dois comandos ( cat FILENAME ) é sempre a mesma e apenas imprime o conteúdo do arquivo especificado no fluxo STDOUT. Eu não vou explicar mais nada.

O ponto de nosso interesse é a parte grep .

Sintaxe de grep :

grep [OPTIONS] PATTERN [FILE...]

Você pode passar grep algumas opções para ajustar seu comportamento (por exemplo, definir o sabor RegEx usado ou controlar a formatação de saída), mas elas não são usadas no seu caso.

O próximo argumento único deve ser o padrão a ser correspondido, em que uma expressão regular ("RegEx") ou uma sequência fixa (se grep for chamado com a opção -F ) é obrigatória . No seu exemplo, esta é a parte install ou "\ install\ " . Eu explicarei no próximo parágrafo.

Depois disso, você especifica a origem dos dados para corresponder. Isso pode ser um nome de arquivo ou nada. No segundo caso, grep lerá do fluxo STDIN (entrada padrão: normalmente o que você digita com o teclado), onde você canaliza ( | ) a saída do comando anterior.

Como passar corretamente o argumento "PATTERN"?

O parâmetro padrão deve ser um único argumento. Isso significa que você não pode simplesmente passar várias palavras ou qualquer coisa contendo espaços ou shell de caracteres especiais aqui, porque os espaços são tratados como separadores de argumentos no Bash e provavelmente todos os outros shell também, e os caracteres especiais shell como ; irão quebrar o comando.

Mas você tem duas opções para incluir espaços no padrão para corresponder de qualquer maneira:

  • Coloque a string inteira para corresponder em aspas simples ( '...' ) ou dupla ( "..." ). Dessa forma, o shell analisa toda a string entre aspas como um argumento e a passa para grep .

  • Escape de cada espaço no padrão com uma barra invertida ( \ ). Isso significa que você escreve uma barra invertida antes de cada espaço que você não quer que seja visto como separador de argumentos pelo shell. Mas observe que, se você quiser ter uma barra invertida real no padrão, também deve escapar dela, escrevendo outra barra invertida antes.

Se analisarmos agora a diferença dos seus dois exemplos de comando grep , vemos a diferença no que correspondem:

cat /var/log/dpkg.log | grep "\ install\ "

Isso corresponde ao padrão install . (Observe o espaço inicial e final!)

Aqui, vemos os dois métodos: aspas duplas em torno de todo o padrão e a saída de barra invertida dos espaços dentro dele. É supérfluo, para ser honesto, seria suficiente. Embora não doa, neste caso, você não deve fazer isso e decidir sobre um método. Normalmente eu recomendaria usar aspas, pois é mais fácil de ler.

cat /var/log/dpkg.log | grep install

Isso corresponde ao padrão install . (Sem espaços ao redor.)

Aqui, o padrão consiste apenas na palavra install , nada mais. Sem espaços.

Diferença entre seus comandos:

Como eu disse, o primeiro dos seus exemplos corresponde apenas à palavra install quando está cercada por espaços. Não corresponderia se, e. Há um ponto final ou qualquer outro caractere diretamente antes ou depois dele. Também não corresponderia à palavra diretamente no início ou no final de uma linha.

O segundo exemplo não se preocupa com nenhum espaço antes ou depois da palavra install . Ele também coincide nos começos e finais da linha, bem como se estiver cercado por qualquer pontuação. Corresponde mesmo se houver uma palavra contendo esta sequência de letras em qualquer lugar, por ex. "desinstalar", "reinstalar" ou "instalação" também!

Exemplo com escape de barra invertida correta / útil:

Como no exemplo que você forneceu, as barras invertidas são supérfluas, aqui o mesmo exemplo sem aspas, mas com a barra invertida escapando apenas:

cat /var/log/dpkg.log | grep \ install\ 

Ou se você quiser combinar a string "Eu gosto do Ubuntu" em um arquivo /home/you/path with spaces/textfile sem usar aspas, você faria assim:

grep I\ like\ Ubuntu /home/you/path\ with\ spaces/textfile

Você verá que também deve escapar de espaços em nomes de caminho ou de arquivo ou citá-los. A linha acima é igual à linha abaixo:

grep "I like Ubuntu" "/home/you/path with spaces/textfile"
    
por Byte Commander 21.12.2015 / 18:09
4

A segunda forma (mais simples) corresponderá à determinada string em qualquer lugar de uma linha: assim, por exemplo, ela corresponderá a strings como install ção, re install , instalar ed etc.

A primeira expressão corresponderá apenas a instalação , onde há um espaço em cada extremidade. As barras invertidas são um pouco suspeitas já que as aspas já são suficientes (e a primeira - desnecessariamente - escapa do i em vez do espaço): no entanto, ele poderia ter sido escrito usando apenas escapes de barra invertida como

cat /var/log/dpkg.log | grep \ install\ 

(NB há um caractere de espaço literal no final do comando acima).

Adicionar um único espaço ao padrão é um pouco de hackear IMHO: ele não funcionará se o padrão for separado por outro espaço em branco (guias ou terminações de linha). Uma opção melhor pode ser usar limites de palavras explícitas, por exemplo,

grep '\binstall\b' /var/log/dpkg.log

ou use a opção -w ( --word-regexp )

grep -w 'install' /var/log/dpkg.log

(embora estes incluam hífens e espaços em branco - portanto, a equivalência não é exata). Se você realmente quiser espaços separados por espaços em branco de instâncias do padrão, poderá usar a classe de caractere [[:space:]] POSIX, por exemplo,

grep '[[:space:]]install[[:space:]]' /var/log/dpkg.log
    
por steeldriver 21.12.2015 / 18:07
3

O primeiro comando:

cat /var/log/dpkg.log | grep " \install\ "

Como @ByteCommander apontou, pode haver um erro de digitação e o comando deve ser

cat /var/log/dpkg.log | grep "\ install\ "

Isso corresponderia à string install com um espaço em branco à esquerda e um espaço em branco principal. Isso também pode ser obtido usando grep -w "install" . Além disso, o \ não é necessário quando você usa aspas.

O segundo comando:

cat /var/log/dpkg.log | grep install

Este comando também corresponde a strings, que contêm install . Por exemplo, " install ed".

Caso de teste:
conteúdo do testfile:

foo
bar
foobar
foo bar

Executar:

cat file1.txt | grep foo
foo
foobar
foo bar

cat file1.txt | grep -w foo
foo
foo bar

cat file1.txt | grep "foo "
foo bar
    
por Wayne_Yux 21.12.2015 / 18:10