
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 -F
no funciona porque la línea tiene que comenzar con la cadena (^, que es un carácter simple con -F). Además, getent $user
no 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?
awk
Lo 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 $var
reemplazamos todos los caracteres c
con d
. Ahora, en su caso, c
es [
, 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.ot
como coincidencias de expresión regular, root
por ejemplo).
Además, su enfoque ( getent passwd | grep "^$user:"
) tampoco es válido porque, por ejemplo, no se marcaría root:0
como 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 id
comando (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 id
implementaciones 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 id
anteriores,, ps
... find
))).
Respuesta3
Escapar de caracteres especiales es un poco complicado. En su lugar, puede seleccionar getent
primero 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"
-F
para cadenas fijas, -x
para 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 getent
u 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.