Expressão regular em script bash

Expressão regular em script bash

Esta é a primeira vez que faço scripts bash, então provavelmente estou cometendo um erro fácil.

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

Até agora, eu tenho isso:

#!/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 todos os lugares em que experimentei esse regex, ele funciona. Mas no script bash, ele só gera o $groups, seguido por No match. Então, alguém pode me dizer o que há de errado com isso?

Responder1

De man 7 regex:

Uma expressão entre colchetes é uma lista de caracteres entre "[]". …

… Para incluir um '-' literal, torne-o o primeiro ou o último caractere…. [Todos] outros caracteres especiais, incluindo '\', perdem seu significado especial dentro de uma expressão entre colchetes.

Tentar o regexp com egrep gera 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, é um intervalo, exatamente como [a-z]seria. Você precisa colocar o 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).

editar:Na verdade, isso também depende das configurações de localidade. A página de manual avisa sobre isso:

Os intervalos dependem muito da sequência de agrupamento e os programas portáteis devem evitar depender deles.

Por exemplo:

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

Claro, mesmo que não tenha dado erro, não está fazendo o que você deseja:

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

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

Responder2

Regra geral com regexps (e quaisquer bugs em trechos maiores de código): corte-o e reconstrua-o passo a passo ou use a divisão ao meio - o que funcionar melhor para você.

Nesse caso, o culpado acabou sendo o sublinhado - escapar dele com uma barra invertida fez com que funcionasse.

informação relacionada