103.7 Lição 1
Certificação: |
LPIC-1 |
---|---|
Versão: |
5.0 |
Tópico: |
103 Comandos GNU e Unix |
Objetivo: |
103.7 Pesquisar em arquivos de texto usando expressões regulares |
Lição: |
1 de 2 |
Introdução
Os algoritmos de pesquisa de string são muito usados por diversas tarefas de processamento de dados, a tal ponto que os sistemas operacionais Unix têm sua própria implementação onipresente: as expressões regulares, freqüentemente abreviadas para ERs. As expressões regulares consistem em sequências de caracteres constituindo um padrão genérico usado para localizar e, às vezes, modificar uma sequência correspondente em uma sequência maior de caracteres. As expressões regulares expandem muito a capacidade de:
-
Escrever regras de análise (parsing) para solicitações em servidores HTTP, nginx em particular.
-
Escrever scripts que convertem conjuntos de dados baseados em texto para outro formato.
-
Procurar por ocorrências de interesse em entradas de diário ou documentos.
-
Filtrar documentos de marcação, mantendo o conteúdo semântico.
A expressão regular mais simples contém pelo menos um átomo. Um átomo, assim chamado por ser o elemento básico de uma expressão regular, é apenas um caractere que pode ou não ter um significado especial. A maioria dos caracteres comuns não são ambíguos e retêm seu significado literal, enquanto outros têm um significado especial:
.
(ponto)-
O átomo corresponde a qualquer caractere.
^
(acento circunflexo)-
O átomo corresponde ao início de uma linha.
$
(cifrão)-
O átomo corresponde ao fim de uma linha.
Por exemplo, a expressão regular bc
, composta pelos átomos literais b
e c
, pode ser encontrada na string abcd
, mas não na string a1cd
. Por outro lado, a expressão regular .c
pode ser encontrada nas strings abcd
e a1cd
, pois o ponto .
corresponde a qualquer caractere.
Os átomos de circunflexo e o cifrão são usados quando apenas as correspondências no início ou no final da string são de interesse. Por essa razão, eles também são chamados de âncoras. Assim, cd
pode ser encontrado em abcd
, mas ^cd
não. Da mesma forma, ab
pode ser encontrado em abcd
, mas ab$
não. O acento circunflexo ^
é um caractere literal, exceto quando no início, e $
é um caractere literal, exceto quando no final da expressão regular.
Expressão de colchetes
Existe outro tipo de átomo denominado expressão de colchetes. Embora não sejam um único caractere, os colchetes []
(incluindo o conteúdo) são considerados um único átomo. Uma expressão de colchetes geralmente é apenas uma lista de caracteres literais delimitados por []
, fazendo com que o átomo corresponda a qualquer caractere único da lista. Por exemplo, a expressão [1b]
pode ser encontrada nas strings abcd
e a1cd
. Para especificar caracteres aos quais o átomo não deve corresponder, a lista deve começar com ^
, como em [^1b]
. Também é possível especificar intervalos de caracteres em expressões de colchetes. Por exemplo, [0−9]
corresponde aos dígitos de 0 a 9 e [a−z]
corresponde a qualquer letra minúscula. Os intervalos devem ser usados com cuidado, pois podem não ser consistentes em diferentes idiomas.
As listas de expressão de colchetes também aceitam classes em vez de apenas caracteres únicos e intervalos. As classes de caracteres tradicionais são:
[:alnum:]
-
Representa um caractere alfanumérico.
[:alpha:]
-
Representa um caractere alfabético.
[:ascii:]
-
Representa um caractere que pertence ao conjunto de caracteres ASCII.
[:blank:]
-
Representa um caractere em branco, ou seja, um espaço ou tabulação.
[:cntrl:]
-
Representa um caractere de controle.
[:digit:]
-
Representa um dígito (de 0 a 9).
[:graph:]
-
Representa qualquer caractere imprimível, exceto espaço.
[:lower:]
-
Representa um caractere em minúsculas.
[:print:]
-
Representa qualquer caractere imprimível, incluindo espaço.
[:punct:]
-
Representa qualquer caractere imprimível que não seja um espaço ou um caractere alfanumérico.
[:space:]
-
Representa os caracteres de espaço em branco: espaço, alimentação de formulário (
\f
), nova linha (\n
), retorno de carro (\r
), tabulação horizontal (\t
) e tabulação vertical (\v
). [:upper:]
-
Representa uma letra maiúscula.
[:xdigit:]
-
Representa dígitos hexadecimais (de 0 a F).
As classes de caracteres podem ser combinadas com caracteres únicos e intervalos, mas não podem ser usadas como ponto final de um intervalo. Além disso, as classes de caracteres podem ser usadas apenas em expressões de colchetes, não como um átomo independente fora dos colchetes.
Quantificadores
O alcance de um átomo, seja um átomo de caractere único ou um átomo de colchete, pode ser ajustado usando um quantificador de átomo. Os quantificadores de átomos definem seqüências de átomos, ou seja, as correspondências ocorrem quando uma repetição contígua para o átomo é encontrada na string. A substring que casa com a correspondência é chamada de peça. Não obstante, quantificadores e outros recursos de expressões regulares são tratados de maneira diferente dependendo do padrão que está sendo usado.
Conforme definido pelo POSIX, existem duas formas de expressões regulares: expressões regulares “básicas” e expressões regulares “estendidas”. A maioria dos programas que trabalham com texto, em qualquer distribuição Linux convencional, oferece suporte a ambas as formas, por isso é importante conhecer as diferenças para evitar problemas de compatibilidade e escolher a implementação mais adequada para a tarefa em questão.
O quantificador *
tem a mesma função em ERs básicas e estendidas (o átomo ocorre zero ou mais vezes) e é um caractere literal se aparecer no início da expressão regular ou se for precedido por uma barra invertida \
. O quantificador de sinal de mais ` seleciona as peças que contêm uma ou mais correspondências de átomos em sequência. Com o quantificador de ponto de interrogação `?`, a correspondência ocorrerá se o átomo correspondente aparecer uma vez ou se não aparecer. Se precedido por uma barra invertida `\`, seu significado especial não é considerado. As expressões regulares básicas também suportam os quantificadores `
e ?
, mas eles precisam ser precedidos por uma barra invertida. Ao contrário das expressões regulares estendidas, +
e ?
sozinhos são caracteres literais em expressões regulares básicas.
Chaves
As chaves são quantificadores que permitem ao usuário especificar limites precisos de quantidade para um átomo. Em expressões regulares estendidas, as chaves podem aparecer de três maneiras:
{i}
-
O átomo deve aparecer exatamente
i
vezes (sendoi
um número inteiro). Por exemplo,[[:blank:]]{2}
corresponde a exatamente dois caracteres em branco. {i,}
-
O átomo deve aparecer pelo menos
i
vezes (sendoi
um número inteiro). Por exemplo,[[:blank:]]{2,}
corresponde a qualquer sequência de dois ou mais caracteres em branco. {i,j}
-
O átomo deve aparecer ao menos
i
vezes e no máximoj
vezes (i
ej
sendo números inteiros,j
maior quei
). Por exemplo,xyz{2,4}
corresponde à stringxy
seguida por dois a quatro caracteresz
.
De toda forma, se uma substring corresponder a uma expressão regular e uma substring mais longa começando no mesmo ponto também corresponder, a substring mais longa será considerada.
As expressões regulares básicas também suportam chaves, mas elas devem ser precedidas por \
: \{
e \}
. Sozinhas, {
e }
são interpretadas como caracteres literais. Uma \{
seguida por um caractere diferente de um dígito é um caractere literal, não uma abertura de chave.
Alternâncias e agrupamentos
As expressões regulares básicas também diferem das expressões regulares estendidas em outro aspecto importante: uma expressão regular estendida pode ser dividida em alternâncias (branches), sendo cada uma delas uma expressão regular independente. As alternativas são separadas por |
e a expressão regular combinada corresponderá a qualquer coisa que corresponda a qualquer uma das alternativas. Por exemplo, he|him
irá corresponder se a substring he
ou a substring him
forem encontradas na string que está sendo examinada. As expressões regulares básicas interpretam |
como um caractere literal. No entanto, a maioria dos programas que suportam expressões regulares básicas permitem alternâncias com \|
.
Uma expressão regular estendida entre ()
pode ser usada em um agrupamento (back reference). Por exemplo, ([[:digit:]])\1
corresponde a qualquer expressão regular que se repita pelo menos uma vez, porque o \1
na expressão é o agrupamento da peça encontrada pela primeira subexpressão entre parênteses. Se houver mais de uma subexpressão entre parênteses na expressão regular, elas podem ser referenciadas com \2
, \3
e assim por diante.
Para ERs básicas, as subexpressões devem ser colocadas entre \(
e \)
, sendo (
and )
sozinhos caracteres comuns. O indicador de agrupamento é usado como nas expressões regulares estendidas.
Pesquisas com expressões regulares
A vantagem imediata oferecida pelas expressões regulares é aprimorar as pesquisas em sistemas de arquivos e em documentos de texto. A opção -regex
do comando find
permite testar cada caminho em uma hierarquia de diretórios de acordo com uma expressão regular. Por exemplo,
$ find $HOME -regex '.*/\..*' -size +100M
busca por arquivos maiores que 100 megabytes (100 unidades de 1048576 bytes), mas apenas em caminhos dentro do diretório inicial do usuário que contenham uma correspondência com .*/\..*
, ou seja, um /.
rodeado por qualquer outro número de caracteres. Em outras palavras, apenas os arquivos ocultos ou arquivos dentro de diretórios ocultos serão listados, independentemente da posição de /.
no caminho correspondente. Para expressões regulares que não diferenciam maiúsculas de minúsculas, a opção -iregex
deve ser usada em seu lugar:
$ find /usr/share/fonts -regextype posix-extended -iregex '.*(dejavu|liberation).*sans.*(italic|oblique).*' /usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf /usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf /usr/share/fonts/liberation/LiberationSans-Italic.ttf
Neste exemplo, a expressão regular contém alternâncias (escritas no estilo estendido) para listar apenas arquivos de fonte específicos na hierarquia de diretório /usr/share/fonts
. Expressões regulares estendidas não são suportadas por padrão, mas find
permite que sejam habilitadas com -regextype posix-extended
or -regextype egrep
. A ER padrão para find
é findutils-default, que é essencialmente um clone da expressão regular básica.
Freqüentemente, é necessário passar a saída de um programa para o comando less
quando ele não cabe na tela. O comando less
divide a entrada em páginas, uma tela de cada vez, permitindo ao usuário navegar facilmente pelo texto para cima e para baixo. Além disso, less
também permite que um usuário execute pesquisas baseadas em expressões regulares. Este recurso é notavelmente importante porque less
é o paginador padrão usado para muitas tarefas diárias, como inspecionar entradas de diário ou consultar páginas de manual. Ao ler uma página de manual, por exemplo, pressionar a tecla / abre um prompt de pesquisa. Esse é um cenário típico em que as expressões regulares são úteis, pois as opções do comando são listadas logo após a margem da página no layout geral da página do manual. No entanto, a mesma opção pode aparecer muitas vezes no texto, inviabilizando as buscas literais. Independentemente disso, digitar ^[[:blank:]]*-o
— ou, mais simplesmente: ^ *-o
— no prompt de pesquisa permite pular imediatamente para a opção da seção -o
(se existente) após pressionar Enter, permitindo assim consultar mais rapidamente uma descrição da opção.
Exercícios Guiados
-
Qual expressão regular estendida corresponderia a qualquer endereço de e-mail, como
info@example.org
? -
Qual expressão regular estendida corresponderia apenas a qualquer endereço IPv4 no formato pontilhado-quad padrão, como
192.168.15.1
? -
Como o comando
grep
pode ser usado para listar o conteúdo do arquivo/etc/services
, descartando todos os comentários (linhas começando com#
)? -
O arquivo
domains.txt
contém uma lista de nomes de domínio, um por linha. Como o comandoegrep
seria usado para listar apenas domínios.org
or.com
?
Exercícios Exploratórios
-
A partir do diretório atual, como o comando
find
usaria uma expressão regular estendida para pesquisar todos os arquivos que não contêm um sufixo de arquivo padrão (nomes de arquivo que não terminam em.txt
ou.c
, por exemplo)? -
O comando
less
é o paginador padrão para exibir arquivos de texto longos no ambiente shell. Ao digitar/
, uma expressão regular pode ser inserida no prompt de pesquisa para pular para a primeira correspondência pertinente. Para permanecer na posição atual do documento e destacar apenas as correspondências pertinentes, qual combinação de teclas deve ser inserida no prompt de pesquisa? -
Em
less
, como seria possível filtrar a saída para que apenas as linhas que correspondem a uma expressão regular sejam exibidas?
Resumo
Esta lição cobre o suporte geral do Linux para expressões regulares, um padrão amplamente usado cujos recursos de correspondência de padrões são suportados pela maioria dos programas que trabalham com texto. A lição atravessa as seguintes etapas:
-
O que é uma expressão regular.
-
Os principais componentes de uma expressão regular.
-
As diferenças entre expressões regulares e expressões regulares estendidas.
-
Como realizar pesquisas simples de texto e arquivos usando expressões regulares.
Respostas aos Exercícios Guiados
-
Qual expressão regular estendida corresponderia a qualquer endereço de e-mail, como
info@example.org
?egrep "\S+@\S+\.\S+"
-
Qual expressão regular estendida corresponderia apenas a qualquer endereço IPv4 no formato pontilhado-quad padrão, como
192.168.15.1
?egrep "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
-
Como o comando
grep
pode ser usado para listar o conteúdo do arquivo/etc/services
, descartando todos os comentários (linhas começando com#
)?grep -v ^# /etc/services
-
O arquivo
domains.txt
contém uma lista de nomes de domínio, um por linha. Como o comandoegrep
seria usado para listar apenas domínios.org
or.com
?egrep ".org$|.com$" domains.txt
Respostas aos Exercícios Exploratórios
-
A partir do diretório atual, como o comando
find
usaria uma expressão regular estendida para pesquisar todos os arquivos que não contêm um sufixo de arquivo padrão (nomes de arquivo que não terminam em.txt
ou.c
, por exemplo)?find . -type f -regextype egrep -not -regex '.*\.[[:alnum:]]{1,}$'
-
O comando
less
é o paginador padrão para exibir arquivos de texto longos no ambiente shell. Ao digitar/
, uma expressão regular pode ser inserida no prompt de pesquisa para pular para a primeira correspondência pertinente. Para permanecer na posição atual do documento e destacar apenas as correspondências pertinentes, qual combinação de teclas deve ser inserida no prompt de pesquisa?Pressionando Ctrl+K antes de inserir a expressão de pesquisa.
-
Em
less
, como seria possível filtrar a saída para que apenas as linhas que correspondem a uma expressão regular sejam exibidas?Pressionando & e inserindo a expressão de pesquisa.