Regex e comandos canalizados com sed

2

Estou achando muito difícil usar o comando sed , além de não conseguir encontrar tutoriais bem escritos.

Deixe-me dizer que trabalhei com expressão regular em outras linguagens (Python, JavaScript, Java), de modo que não deveria ser o problema.

Então, aqui estão minhas perguntas (uma "teórica" e outra mais prática):

  1. as expressões regulares são usadas em sed exatamente iguais às usadas pelo Python / JS / Java? Eu li sobre BREs e EREs, mas quanto eles são diferentes? O ERE não deveria ser uma extensão do BRE?

  2. se eu quiser, digamos, apenas extrair algo de uma saída canalizada, qual é a sintaxe sed para fazer isso?

Detalhes sobre a segunda pergunta: digamos que eu tenha a saída de uptime piped com sed:

uptime | sed ...

Dado um exemplo de saída de uptime : 18:13 up 5:12, 2 users, load averages: 0,45 0,37 0,40 , quero analisar o tempo de atividade único na forma de dois números separados (horas e minutos) e, em seguida, quero exibi-los na forma de xxhyym ( xx são as horas, yy os minutos).

E, para finalizar, eis o que eu faria em Python:

hh, mm = re.match(r'\s+ up \s+(\d{1,2}):(\d{1,2})').groups()
print '%sh%sm' % (hh, mm)
    
por whatyouhide 26.03.2013 / 18:16

2 respostas

4

As ferramentas tradicionais unix suportam BRE ou ERE (expressões regulares básicas ou estendidas). POSIX codifica ambos. Wikipedia explica-os. A maioria das ferramentas modernas estende ERE, muitas vezes com recursos adicionais introduzidos pela primeira vez em Perl (que é conhecido como PCRE ).

O ERE estende a funcionalidade do BRE, mas não estende a sintaxe. No BRE, apenas os caracteres \[.*^$ têm um significado especial e alguns operadores, como o agrupamento \(…\) , usam barras invertidas. No ERE, +?|() também são especiais, e a barra invertida seguida por um caractere não alfanumérico nunca é especial.

O BRE não tem \d e \s do Python / PCRE. Você pode expressar esses conjuntos de caracteres com construções de conjuntos tradicionais e classes de caracteres: \d is [[:digit:]] e \s is [[:space:]] . Observe os colchetes duplos: um para indicar um conjunto de caracteres e outro para indicar uma classe de caractere; por exemplo, "letras, traços ou sublinhados" podem ser escritos [-_[:alpha:]] .

O BRE não tem um operador + (algumas implementações de sed suportam \+ como extensão da sintaxe BRE); X+ é o mesmo que XX* . Os grupos e as correspondências precisam de barras invertidas adicionais.

O equivalente a BRE do \s+ up \s+(\d{1,2}):(\d{1,2}) do Python é, portanto, [[:space:]][[:space:]]* up [[:space:]][[:space:]]*\([[:digit:]]\{1,2\}\):\([[:digit:]]\{1,2\}\) . Observe que você está combinando muito espaço em branco: \s+ e um espaço significa pelo menos dois caracteres em branco.

Você precisará corresponder à linha inteira, pois o comando s do sed reconfigura a linha. Não há um comando separado para escrever uma string montada a partir de grupos salvos. Corrigindo o espaço em branco extra, o análogo do seu snippet do Python é:

uptime | sed 's/^.*[[:space:]][[:space:]]*up[[:space:]][[:space:]]*\([[:digit:]]\{1,2\}\):\([[:digit:]]\{1,2\}\).*$/hm/'

Ao contrário do snippet Python, isso extrai a primeira correspondência em vez da última, mas não importa aqui.

A saída de uptime fica em caracteres de espaço e dígitos ASCII, portanto, você pode simplificar o regex:

uptime | sed 's/^.* up  *\([0-9]\{1,2\}\):\([0-9]\{1,2\}\).*$/hm/'

Isso só corresponderá à saída de uptime se a máquina estiver ativa por menos de 1 dia. Vou deixar coincidindo o número de dias como um exercício. (Dica: escreva duas expressões: sed -e s/AS ABOVE/hm/ -e 's/EXERCISE/dhm/' )

    
por 27.03.2013 / 00:27
1

Cada ferramenta usa (principalmente) sua própria biblioteca de RE. Mesmo entre diferentes versões sed , você encontrará diferenças aqui. Dois padrões populares são as expressões regulares padrão POSIX, muitas ferramentas aceitam essas (pelo menos com algumas opções), outro conjunto popular é a biblioteca Perreg Compatible Regular Expression (PCRE). Mas os últimos são um pouco diferentes dos REs "vanilla" ...

No seu caso:

uptime | sed -e 's/^ \([0-9][0-9]\):\([0-9][0-9]\).*$/hm/'

(Tentei no Fedora 18, sed-4.2.1-10.fc18.x86_64, GNU sed).

Atualização: O que há de errado com a copiosa documentação na página inicial do GNU sed ? Ou este tutorial ? A documentação informativa do GNU sed é um pouco prolixa, mas completa.

    
por 26.03.2013 / 18:30