Expressão regular no script bash

13

Esta é a minha primeira vez que estou provavelmente cometendo um erro fácil.

Basicamente, estou tentando escrever um script que obtenha os grupos de um usuário e, se estiverem em um determinado grupo, ele registrará isso de acordo. Evidentemente, haverá mais funcionalidade, mas não faz sentido construir isso quando não consigo nem mesmo fazer o regex funcionar!

Até agora, tenho isto:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Em todo lugar que eu tentei, regex, funciona. Mas no script bash, ele sempre gera o $groups , seguido por No match . Então alguém pode me dizer o que há de errado com isso?

    
por jrdn 03.10.2013 / 16:09

2 respostas

14

De man 7 regex :

A bracket expression is a list of characters enclosed in "[]". …

… To include a literal '-', make it the first or last character…. [A]ll other special characters, including '\', lose their special significance within a bracket expression.

Tentar o regexp com o egrep dá um erro:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Aqui está uma versão mais simples, que também dá um erro:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

Como \ não é especial, isso é um intervalo, assim como [a-z] seria. Você precisa colocar seu - no final, como [_-] ou:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Isso deve funcionar independentemente da sua versão da libc (em egrep ou bash).

edit: Isso também depende de suas configurações de localidade. A manpage adverte sobre isso:

Ranges are very collating-sequence-dependent, and portable programs should avoid relying on them.

Por exemplo:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

É claro que, mesmo sem erros, não está fazendo o que você quer:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

É um intervalo que, em ASCII, inclui \ , [ , ^ e _ .

    
por 03.10.2013 / 17:29
4

Regra geral com regexps (e quaisquer erros em pedaços maiores de código): reduza-o e reconstrua-o passo a passo ou use bissecto - o que for melhor para você.

Neste caso, o culpado acabou por ser o sublinhado - escapá-lo com uma barra invertida fez com que funcionasse.

    
por 03.10.2013 / 17:16