Escapar [en grep

Escapar [en grep

Leo cadenas de stdin y quiero mostrar los usuarios que coinciden con las cadenas. El problema es si el usuario ingresa el carácter '[' o una cadena que lo contiene.

grep -Fno funciona porque la línea tiene que comenzar con la cadena (^, que es un carácter simple con -F). Además, getent $userno será bueno porque solo necesito el nombre de usuario, no la identificación.

if [[ "$user" == *"["* ]]; then
    echo -e "Invalid username.\n"
    continue
fi

if ! getent passwd | grep "^$user:"; then
    echo -e "Invalid username.\n"
    continue
fi

Esta es la solución para '[', ¿hay otra manera? awkLo más probable es que haga el trabajo, pero aún no lo sé, estoy interesado en grep.

Respuesta1

Escápelo o póngalo en una clase de personaje, algo como esto:

grep '\['

grep '[[]'

grep -e "${user//\[/\\\[}"

La sintaxis ${var//c/d}=> en la variable shell $varreemplazamos todos los caracteres ccon d. Ahora, en su caso, ces [, pero resulta que [es especial en esta sintaxis (hace globbing) y, por lo tanto, debemos escapar de él anteponiéndolo con una barra invertida, es decir, \[.

Ahora, pasando a la pieza de repuesto, lo que necesitamos es una pieza \[de allí. Pero nuevamente, ambos \y [son especiales en esta sintaxis de ${var//...}sustitución de parámetros y, por lo tanto, ambos deben tener, sí, lo adivinaste bien, una barra invertida que conduce a la expresión \\\[: "${var//\[/\\\[}"

HT

Respuesta2

[no es el único personaje que escapa de las expresiones regulares. Todos los operadores RE incluyen .lo que es común en los nombres de usuario ( r.otcomo coincidencias de expresión regular, rootpor ejemplo).

Además, su enfoque ( getent passwd | grep "^$user:") tampoco es válido porque, por ejemplo, no se marcaría root:0como no válido.

Aquí sería mejor utilizar awk:

user_valid() {
  getent passwd | 
    U="$1" awk -F: '$1 == ENVIRON["U"] {found = 1; exit}
                    END {exit(1 - found)}'
}

Ahora bien, no todas las bases de datos de usuarios permiten una enumeración como esa.

$ getent passwd | grep stephane
$ id -u stephane
10631
$ getent passwd stephane
stephane:*:10631:10631:Stephane Chazelas:/export/./home/stephane:/bin/zsh

En mi caso, ese usuario está en una base de datos LDAP.enumeraciónestá deshabilitado (podría haber miles de usuarios), pero aún puedo consultar/resolver usuarios individualmente.

Entonces, para validar a los usuarios, es mejor consultar la base de datos de usuarios directamente para ese usuario. Por ejemplo, usando el idcomando (un comando estándar contrario a getent):

user_valid() {
  case $1 in
    (*[!0-9]*) id -u -- "$1" > /dev/null 2>&1;;
    (*) false;;
  esac
}

(Nos ocupamos de los usuarios de todos los dígitos por separado, ya que algunas idimplementaciones le brindarían información para la identificación del usuario en ese caso. Los nombres de usuario no pueden ser numéricos en la mayoría de los sistemas (eso interrumpiría la mayoría de los comandos que esperan nombres de usuario o usuarios). identificadores como argumentos (como los idanteriores,, ps... find))).

Respuesta3

Escapar de caracteres especiales es un poco complicado. En su lugar, puede seleccionar getentprimero el campo de nombre de usuario de la salida de y luego compararlo con la línea restante completa:

LC_ALL=C
if ! [[ $user =~ ^[A-Za-z0-9._][A-Za-z._-]*$ ]] ; then
    echo "Username is invalid"
    continue
fi
getent passwd | cut -d: -f1 | grep -xF -e "$user"

-Fpara cadenas fijas, -xpara coincidencia de línea completa.

Si no tiene usuarios con nombres de usuario que consistan únicamente en dígitos, puede usar getent:

LC_ALL=C
if ! [[ $user =~ ^[A-Za-z0-9._][A-Za-z._-]*$ ]] ; then
    echo "Username is invalid"
    continue
elif [[ $user =~ ^[0-9]+$ ]] ; then
    echo "Cannot handle username of digits only, sorry :("
    continue
fi
if ! getent -- passwd "$user" > /dev/null ; then
    echo "$user doesn't exist"
    continue
fi

O, para evitar problemas con getentu otros asumiendo que una cadena de dígitos debe ser un UID en lugar de un nombre de usuario, deberíamos llamargetpwnam()a mano. Esto no supone otras suposiciones sobre cuáles pueden ser los nombres de usuario, aparte de lo que getpwnam()hace la implementación subyacente.

export user
if ! perl -e 'exit !defined getpwnam($ENV{user})' ; then 
    echo "$user doesn't exist"
fi

Saltaré la escritura del contenedor C correspondiente.

información relacionada