Expresión regular en script bash

Expresión regular en script bash

Esta es la primera vez que hago un script en bash, por lo que probablemente esté cometiendo un error fácil.

Básicamente, estoy tratando de escribir un script que obtenga los grupos de un usuario y, si están en un grupo determinado, lo registrará en consecuencia. Evidentemente, habrá más funciones, ¡pero no tiene sentido crearlas cuando ni siquiera puedo hacer funcionar la expresión regular!

Hasta ahora tengo esto:

#!/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

En todos los lugares donde he probado esa expresión regular, funciona. Pero en el script bash, solo genera $groups, seguido de No match. Entonces, ¿alguien puede decirme qué tiene de malo?

Respuesta1

De man 7 regex:

Una expresión entre corchetes es una lista de caracteres encerrados entre "[]". …

… Para incluir un '-' literal, conviértalo en el primer o último carácter…. [Todos los demás caracteres especiales, incluido '\', pierden su significado especial dentro de una expresión entre corchetes.

Al probar la expresión regular con egrep se produce un error:

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

Aquí hay una versión más simple, que también da un error:

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

Como \no es especial, ese es un rango, tal como [a-z]sería. Necesitas poner tu -al final, como [_-]o:

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

Esto debería funcionar independientemente de su versión de libc (ya sea en egrep o bash).

editar:En realidad, esto también depende de la configuración local. La página de manual advierte sobre esto:

Los rangos dependen mucho de la secuencia de clasificación y los programas portátiles deberían evitar depender de ellos.

Por ejemplo:

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

Por supuesto, aunque no se produjo ningún error, no está haciendo lo que usted desea:

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

Es un rango que en ASCII incluye \, [, ^y _.

Respuesta2

Regla general con expresiones regulares (y cualquier error en fragmentos de código más grandes): córtelo y reconstrúyalo paso a paso o use la bisección, lo que funcione mejor para usted.

En este caso, el culpable resultó ser el guión bajo: escaparlo con una barra invertida hizo que funcionara.

información relacionada