Bash Regex avançado com exemplos

Bash Regex avançado com exemplos

Usando o poder das expressões regulares, pode -se analisar e transformar documentos e strings baseados em textuais. Este artigo é para usuários avançados, que já estão familiarizados com expressões regulares básicas em bash. Para uma introdução às expressões regulares, consulte nossas expressões regulares para iniciantes com exemplos em vez. Outro artigo que você pode achar interessante são expressões regulares em Python.

Pronto para começar? Mergulhe e aprenda a usar regexps como um profissional!

Neste tutorial, você aprenderá:

  • Como evitar pequenas diferenças de sistema operacional de afetar suas expressões regulares
  • Como evitar o uso de padrões de pesquisa de expressão regular muito genéricos como .*
  • Como empregar ou não empregar, sintaxe de expressão regular estendida
  • Exemplos de uso avançado de expressões regulares complexas em bash
Bash Regex avançado com exemplos

Requisitos de software e convenções usadas

Requisitos de software e convenções de linha de comando Linux
Categoria Requisitos, convenções ou versão de software usada
Sistema Independente da distribuição Linux
Programas Linha de comando Bash, sistema baseado em Linux
Outro O utilitário sed é usado como uma ferramenta de exemplo para empregar expressões regulares
Convenções # - requer que os comandos linux -comidos sejam executados com privilégios de raiz diretamente como usuário root ou por uso de sudo comando
$-exige que o Linux-Commands seja executado como um usuário não privilegiado regular

Exemplo 1: Acensão ao usar expressões regulares estendidas

Para este tutorial, usaremos o Sed como nosso principal mecanismo de processamento de expressão regular. Quaisquer exemplos fornecidos geralmente podem ser portados diretamente para outros motores, como os motores de expressão regular incluídos em grep, awk etc.

Uma coisa a ter sempre em mente ao trabalhar com expressões regulares é que alguns mecanismos regex (como o do sed) suportam a sintaxe de expressão regular regular e estendida. Por exemplo, o sed permitirá que você use o -E opção (opção abreviada para --regexp-estendido), permitindo que você use expressões regulares estendidas no script sed.

Praticamente, isso resulta em pequenas diferenças nos idiomas de sintaxe de expressão regular ao escrever scripts de expressão regular. Vejamos um exemplo:

$ echo 'amostra' | sed 's | [a-e] \+| _ | g' s_mpl_ $ echo 'amostra' | sed 's | [a-e]+| _ | g' amostra $ echo 'amostra+' | sed 's | [a-e]+| _ | g' sampl_ $ echo 'amostra' | sed -e 's | [a -e]+| _ | g' s_mpl_ 


Como você pode ver, em nosso primeiro exemplo, usamos \+ Para qualificar a faixa A-C (substituída globalmente devido ao g qualificador) como exigindo uma ou mais ocorrências. Observe que a sintaxe, especificamente, é \+. No entanto, quando mudamos isso \+ para +, O comando produziu uma saída completamente diferente. Isso é porque o + não é interpretado como um personagem padrão e não como um comando regex.

Isso foi posteriormente provado pelo terceiro comando em que um literal +, assim como o e Antes dele, foi capturado pela expressão regular [a-e]+, e transformado em _.

Olhando para trás, o primeiro comando, agora podemos ver como o \+ foi interpretado como uma expressão regular não literal +, a ser processado por sed.

Finalmente, no último comando, dizemos ao SED que queremos especificamente usar sintaxe estendida usando o -E opção de sintaxe estendida para sed. Observe que o termo estendido nos dá uma pista do que acontece em segundo plano; A sintaxe de expressão regular é expandido Para ativar vários comandos regex, como neste caso +.

Uma vez o -E é usado, mesmo que ainda usemos + e não \+, sed interpreta corretamente o + como uma instrução de expressão regular.

Quando você escreve muitas expressões regulares, essas pequenas diferenças em expressar seus pensamentos em expressões regulares desaparecem em segundo plano, e você tenderá a se lembrar dos mais importantes.

Isso também destaca a necessidade de sempre testar expressões regulares extensivamente, dada uma variedade de insumos possíveis, mesmo aqueles que você não espera.

Exemplo 2: Modificação de cordas de serviço pesado

Para este exemplo, e os subsequentes, preparamos um arquivo textual. Se você quiser praticar, pode usar os seguintes comandos para criar este arquivo para si mesmo:

$ echo 'abcdefghijklmnopqrStuvwxyz abcdefg 0123456789'> test1 $ cat test1 abcdefghijklmnopqrststwxyz abcdefg 0123456789 

Vamos agora olhar para o nosso primeiro exemplo de modificações de string: gostaríamos da segunda coluna (ABCDEFG) vir antes do primeiro (a B C D e F G H I J K L M N o p q R S T U V W x y Z).

Como começo, fazemos esta tentativa fictícia:

$ CAT Test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 $ CAT Test1 | sed -e 's | ([a -o]+).*([A-z]+) | \ 2 \ 1 | ' G abcdefghijklmno 0123456789 

Você entende esta expressão regular? Nesse caso, você já é um escritor de expressão regular muito avançado, e pode optar por pular para os seguintes exemplos, ignorando -os para ver se você é capaz de entendê -los rapidamente ou precisa de um pouco de ajuda.

O que estamos fazendo aqui é gato (exibir) nosso arquivo test1 e analisá -lo com uma expressão regular estendida (graças ao -E opção) usando sed. Poderíamos ter escrito essa expressão regular usando uma expressão regular não estendida (em sed) da seguinte maneira;

$ CAT Test1 | sed 's | \ ([a-o] \+\).*\ ([A-z] \+\) | \ 2 \ 1 | ' G abcdefghijklmno 0123456789 

O que é exatamente o mesmo, exceto que adicionamos um \ personagem antes de cada um (, ) e + caráter, indicando que, queremos que eles sejam analisados ​​como código de expressão regular, e não como caracteres normais. Vamos agora dar uma olhada na própria expressão regular.

Vamos usar o formato de expressão regular estendido para isso, pois é mais fácil analisar visualmente.

s | ([a-o]+).*([A-z]+) | \ 2 \ 1 | 

Aqui estamos usando o comando sed substituto (s no início do comando), seguido de uma pesquisa (primeiro |… | parte) e substitua (segundo |… | parte) seção.

Na seção de pesquisa, temos dois grupos de seleção, cada um cercado e limitado por ( e ), nomeadamente ([a-o]+) e ([A-z]+). Esses grupos de seleção, na ordem em que são dados, serão procurados enquanto pesquisam as cordas. Observe que entre o grupo de seleção, temos um .* expressão regular, o que basicamente significa qualquer personagem, 0 ou mais vezes. Isso corresponderá ao nosso espaço entre a B C D e F G H I J K L M N o p q R S T U V W x y Z e ABCDEFG no arquivo de entrada e potencialmente mais.

Em nosso primeiro grupo de pesquisa, procuramos pelo menos uma ocorrência de a-o seguido por qualquer outro número de ocorrências de a-o, indicado pelo + qualificador. No segundo grupo de pesquisa, procuramos cartas maiúsculas entre A e Z, E isso novamente uma ou mais vezes em sequência.

Finalmente, em nossa seção de substituição do sed Comando de expressão regular, nós iremos Ligue/recall O texto selecionado por esses grupos de pesquisa e insira -os como seqüências de substituição. Observe que a ordem está sendo revertida; Primeira saída o texto correspondente pelo segundo grupo de seleção (através do uso de \ 2 indicando o segundo grupo de seleção), então o texto correspondente pelo primeiro grupo de seleção (\ 1).

Embora isso possa parecer fácil, o resultado em mãos (G abcdefghijklmno 0123456789) pode não estar imediatamente claro. Como nos perdemos ABCDEF por exemplo? Nós também perdemos pqrstuvwxyz - Você notou?



O que aconteceu é isso; Nosso primeiro grupo de seleção capturou o texto abcdefghijklmno. Então, dado o .* (qualquer personagem, 0 ou mais vezes) Todos os personagens foram comparados - e isso é importante; na extensão máxima - até encontrarmos a próxima expressão regular de correspondência aplicável, se houver. Então, finalmente, combinamos com qualquer carta fora do A-z alcance, e esta mais uma vez.

Você está começando a ver por que perdemos ABCDEF e pqrstuvwxyz? Embora não seja de forma alguma evidente, o .* continuou combinando com os personagens até o durar A-z foi comparado, o que seria G no ABCDEFG corda.

Mesmo que tenhamos especificado um ou mais (através do uso de +) Personagens a serem correspondidos, essa expressão regular em particular foi corretamente interpretada por sed da esquerda para a direita, e sed apenas parou com a correspondência de qualquer personagem (.*) quando não poderia mais cumprir a premissa de que haveria pelo menos um maiúsculas A-z personagem próximo.

No total, pqrstuvwxyz abcdef foi substituído por .* Em vez de apenas o espaço, como alguém lia essa expressão regular em uma leitura mais natural, mas incorreta. E, porque não estamos capturando o que foi selecionado por .*, Esta seleção foi simplesmente retirada da saída.

Observe também que todas as partes não correspondidas pela seção de pesquisa são simplesmente copiadas para a saída: sed só agirá em qualquer que seja a expressão regular (ou correspondência de texto) achados.

Exemplo 3: selecionar tudo o que não é

O exemplo anterior também nos leva a outro método interessante, que você provavelmente usará um pouco se escrever expressões regulares regularmente, e isso está selecionando texto por meio de correspondência Tudo isso não é. Parece uma coisa divertida de se dizer, mas não está claro o que significa? Vejamos um exemplo:

$ CAT Test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 $ CAT Test1 | sed -e 's | [^]*| _ |' _ ABCDEFG 0123456789 

Uma simples expressões regulares, mas muito poderosa. Aqui, em vez de usar .* de alguma forma ou moda que usamos [^]*. Em vez de dizer (por .*) Combine qualquer personagem, 0 ou mais vezes, nós agora declaramos corresponder a qualquer caractere não espacial, 0 ou mais vezes.

Embora isso pareça relativamente fácil, você em breve perceberá o poder de escrever expressões regulares dessa maneira. Pense por exemplo, sobre o nosso último exemplo, no qual de repente temos grande parte do texto correspondente de uma maneira um tanto inesperada. Isso pode ser evitado mudando ligeiramente nossa expressão regular do exemplo anterior, como segue:

$ CAT Test1 | sed -e 's | ([a-o]+) [^a]+([a-z]+) | \ 2 \ 1 |' Abcdefg abcdefghijklmno 0123456789 

Ainda não é perfeito, mas melhor; Pelo menos fomos capazes de preservar ABCDEF papel. Tudo o que fizemos foi mudar .* para [^A]+. Em outras palavras, continue procurando personagens, pelo menos um, exceto A. Uma vez A descobriu -se que parte das paradas de análise de expressão regular. A em si também não será incluído na partida.

Exemplo 4: Voltando ao nosso requisito original

Podemos fazer melhor e de fato trocar a primeira e a segunda colunas corretamente?

Sim, mas não mantendo a expressão regular como está. Afinal, está fazendo o que solicitamos a fazer; combinar todos os personagens de a-o Usando o primeiro grupo de pesquisa (e saída posteriormente no final da string) e depois descartar Qualquer personagem até o sed atingir A. Poderíamos fazer uma resolução final da questão - lembre -se de que queríamos que apenas o espaço fosse correspondido - estendendo/alterando o a-o para a-z, Ou simplesmente adicionando outro grupo de pesquisa e combinando o espaço literalmente:

$ CAT Test1 | sed -e 's | ([a-o]+) ([^]+) [] ([a-z]+) | \ 3 \ 1 \ 2 |' Abcdefg abcdefghijklmnopqrstuvwxyz 0123456789 

Ótimo! Mas a expressão regular parece muito complexa agora. Nós combinamos a-o Uma ou mais vezes no primeiro grupo, então qualquer personagem não espacial (até que o sed encontre um espaço ou o fim da corda) no segundo grupo, depois um espaço literal e finalmente A-z Uma ou mais vezes.

Podemos simplificar isso? Sim. E isso deve destacar como se pode facilmente complicar scripts de expressão regular.

$ CAT Test1 | sed -e 's | ([^]+) ([^]+) | \ 2 \ 1 |' Abcdefg abcdefghijklmnopqrststwxyz 0123456789 $ CAT Test1 | awk 'print $ 2 "" $ 1 "" $ 3' abcdefg abcdefghijklmnopqrstuvwxyz 0123456789 


Ambas as soluções atingem o requisito original, usando ferramentas diferentes, um regex muito simplificado para o comando sed e sem bugs, pelo menos para as seqüências de entrada fornecidas. Isso pode dar errado facilmente?

$ CAT Test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 $ CAT Test1 | sed -e 's | ([^]+) ([^]+) | \ 2 \ 1 |' abcdefghijklmnopqrstuvwxyz 0123456789 abcdefg 

Sim. Tudo o que fizemos foi adicionar um espaço adicional na entrada e, usando a mesma expressão regular, nossa saída agora está completamente incorreta; a segunda e a terceira colunas foram trocadas em vez do punho dois. Novamente, a necessidade de testar expressões regulares em profundidade e com entradas variadas é destacada. A diferença na saída é simplesmente porque o padrão sem espaço sem espaço só poderia ser correspondido pela última parte da sequência de entrada devido ao espaço duplo.

Exemplo 5: LS Gotcha?

Às vezes, uma configuração de nível de sistema operacional, como por exemplo, usando a saída de cores para listagens de diretórios ou não (que podem ser definidas por padrão!), fará com que os scripts da linha de comando se comportem de forma irregular. Embora não seja uma falha direta de expressões regulares por qualquer meio, é um Gotcha que se pode encontrar mais facilmente ao usar expressões regulares. Vejamos um exemplo:

A saída de cor LS mancha o resultado de um comando contendo expressões regulares
$ ls -d t* test1 test2 $ ls -d t* 2 | sed 's | 2 | 1 |' Test1 $ ls -d t*2 | sed 's | 2 | 1 |' | XARGS LS LS: Não é possível acessar "

Neste exemplo, temos um diretório (test2) e um arquivo (test1), ambos sendo listados pelo original LS -D comando. Em seguida, pesquisamos todos os arquivos com um padrão de nome de arquivo de T*2, e remova os 2 do nome do arquivo usando sed. O resultado é o texto teste. Parece que podemos usar esta saída teste imediatamente para outro comando, e nós o enviamos via Xargs para o ls comando, esperando o ls comando para listar o arquivo Test1.

No entanto, isso não acontece e, em vez disso, obtemos uma saída muito complexa a humana. O motivo é simples: o diretório original foi listado em uma cor azul escura, e essa cor é definida como uma série de códigos de cores. Quando você vê isso pela primeira vez, é difícil entender a saída. A solução, no entanto, é simples;

$ ls -d - -cor = nunca t*2 | sed 's | 2 | 1 |' | XARGS LS Test1 

Nós fizemos o ls saída de comando a listagem sem usar nenhuma cor. Isso corrige completamente o problema em questão e nos mostra como podemos manter no fundo de nossas mentes a necessidade de evitar pequenas, mas significativas, configurações específicas e gotchas, o que pode quebrar nosso trabalho de expressão regular quando executado em diferentes ambientes, em em diferentes ambientes, em hardware diferente, ou em diferentes sistemas operacionais.

Pronto para explorar ainda mais por conta própria? Vejamos algumas das expressões regulares mais comuns disponíveis em Bash:

Expressão Descrição
. Qualquer personagem, exceto newline
[A-C] Um personagem do intervalo selecionado, neste caso A, B, C
[A-Z] Um personagem do intervalo selecionado, neste caso A-Z
[0-9AF-Z] Um personagem do intervalo selecionado, neste caso 0-9, A e F-Z
[^A-za-z] Um caractere fora do intervalo selecionado, neste caso, por exemplo, '1' se qualificaria
\* ou * Qualquer número de correspondências (0 ou mais). Use * ao usar expressões regulares onde expressões estendidas não estão ativadas (veja o primeiro exemplo acima)
\+ ou + 1 ou mais correspondências. Idem Comentário como *
\ (\) Grupo de captura. A primeira vez que isso é usado, o número do grupo é 1, etc.
^ Início da string
$ Final da string
\ d Um dígito
\ D Um não dígito
\ s Um espaço branco
\ S Um espaço não branco
a | d Um personagem dos dois (uma alternativa ao uso []), 'a' ou 'd'
\ Escapa de caracteres especiais ou indica que queremos usar uma expressão regular onde expressões estendidas não estão ativadas (veja o primeiro exemplo acima)
\ b Personagem do backspace
\ n Personagem newline
\ r Caráter de retorno do carro
\ t Caractere de guia

Conclusão

Neste tutorial, procuramos profundidade nas expressões regulares da Bash. Descobrimos a necessidade de testar nossas expressões regulares, com entradas variadas. Também vimos como as pequenas diferenças do sistema operacional, como usar a cor para ls comandos ou não, pode levar a resultados muito inesperados. Aprendemos a necessidade de evitar padrões de pesquisa de expressão regular demais e como usar expressões regulares estendidas.

Desfrute de escrever expressões regulares avançadas e deixe um comentário abaixo com seus exemplos mais legais!

Tutoriais do Linux relacionados:

  • Bash regexps para iniciantes com exemplos
  • Expressões regulares do Python com exemplos
  • Manipulação de big data para diversão e lucro Parte 3
  • Uma introdução à automação, ferramentas e técnicas do Linux
  • Coisas para instalar no Ubuntu 20.04
  • Manipulação de big data para diversão e lucro Parte 2
  • Manipulação de big data para diversão e lucro Parte 1
  • Mastering Bash Script Loops
  • Mint 20: Melhor que o Ubuntu e o Microsoft Windows?
  • Coisas para fazer depois de instalar o Ubuntu 20.04 fossa focal linux