A sintaxe do grep é diferente da expressão regular?

2

Eu quero extrair o nome dos pacotes removidos daqui "cat /var/log/dpkg.log | grep 'remove'"

 2013-09-09 15:57:34 remove activity-log-manager:i386 0.9.4-0ubuntu6.2 <none>
 2013-09-09 15:57:35 remove activity-log-manager-control-center:i386 0.9.4-0ubuntu6.2 <none>
 2013-09-09 15:57:38 remove alacarte:all 3.6.1-0ubuntu3 <none>
 2013-09-09 15:57:41 remove deepin-software-center:all 2.1.2.1~precise~NoobsLab.com <none>

Eu quero pegar apenas o nome dos pacotes entre remover e dois pontos após o nome do pacote. Eu não sou um especialista em regex, eu fiz uma expressão regex que parece fazer o trabalho, mas quando eu quero aplicá-lo com o grep nada acontece. Aqui está trabalhando padrão de regex em avaliadores de regex

(?<=remove)(.*?)(?=:)

Mas isso não está funcionando:

cat /var/log/dpkg.log | grep 'remove' | grep '(?<=remove)(.*?)(?=:)'

O que estou perdendo aqui?

    
por kenn 22.09.2013 / 13:10

2 respostas

6

Há um núcleo comum de sintaxe de expressão regular, no entanto, existem sabores distintos. Sua expressão parece conter alguns recursos específicos do sabor perl, em particular o uso de asserções complexas lookaround descrevendo o início e o fim do padrão a ser correspondido, enquanto o grep usa uma expressão regular básica (BRE ) sintaxe que suporta apenas um conjunto mais simples dessas correspondências de comprimento zero , como line- ( ^ , $ ) e âncoras de palavras ( \> , \< ).

Você pode ativar o suporte à expressão regular compatível com perl (PCRE) no grep usando a opção de linha de comando -P (embora observe que a página man atualmente a descreve como "experimental"). No seu caso, você provavelmente quer que o switch -o também imprima apenas o padrão de correspondência, ao invés de toda a linha, ou seja,

cat /var/log/dpkg.log | grep 'remove' | grep -oP '(?<=remove)(.*?)(?=:)'

Esteja ciente de que esta expressão pode falhar se encontrar pacotes que não tenham o sufixo: i386, uma vez que ele pode ler adiante para os dois pontos correspondentes na próxima palavra, por exemplo,

echo "2013-09-07 08:31:44 remove cifs-utils 2:5.1-1ubuntu2 <none>" | grep -oP '(?<=remove)(.*?)(?=:)'
 cifs-utils 2

Você pode querer olhar para o awk, por exemplo,

cat /var/log/dpkg.log | awk ' ~ /remove/ {sub(":.*", "", ); print }'

Assim como o BRE e o PCRE, o Gnu grep tem um outro modo chamado expressão regular estendida (ERE), especificado pela opção de linha de comando -E. A página man observa que

In  GNU grep,  there is  no difference in available functionality 
between basic and extended syntaxes.

No entanto, você deve observar que "nenhuma diferença na funcionalidade disponível" não não significa que a sintaxe é a mesma. Por exemplo, no BRE, o caractere + é normalmente tratado como literal e só se torna um modificador que significa 'uma ou mais instâncias da expressão regular precedente' se for escapado, ou seja,

$ echo "123.456" | grep '[0-9]+\.[0-9]+'
$ echo "123.456" | grep '[0-9]\+\.[0-9]\+'
123.456

enquanto que para o ERE é exatamente o oposto

$ echo "123.456" | grep -E '[0-9]+\.[0-9]+'
123.456
$ echo "123.456" | grep -E '[0-9]\+\.[0-9]\+'

Uma distinção semelhante se aplica a sed chamado sem e com a opção -r .

    
por steeldriver 22.09.2013 / 15:35
0

Na página grep man:

  

grep pesquisa os FILEs de entrada nomeados (ou entrada padrão se nenhum arquivo é nomeado, ou se um único hífen-menos (-) é dado como nome do arquivo) para linhas contendo uma correspondência para o PATTERN dado.

Até onde eu sei, grep não tem capacidade de editar as linhas correspondentes; Eu usaria sed ou possivelmente tr para isso. Qualquer um dos itens a seguir deve conseguir o que você deseja:

cat /var/log/dpkg.log | grep 'remove' | sed 's/.*remove \([^:]*\):.*//'
cat /var/log/dpkg.log | grep 'remove' | sed -E 's/.*remove ([^:]*):.*//'
cat /var/log/dpkg.log | sed -n '/remove/s/.*remove \([^:]*:\).*//p'
cat /var/log/dpkg.log | sed -nE '/remove/s/.*remove ([^:]*):.*//p'

Honestamente, não tenho certeza do que seu (?<=remove)(.*?)(?=:) está tentando realizar. Na regex, colchetes são usados para definir grupos de captura: você pode ver que eu usei-os nos comandos sed aqui - lá, tudo combinado será substituído pelo conteúdo do grupo de captura /1 , o primeiro grupo a ser definido.

    
por evilsoup 22.09.2013 / 15:24