
Eu leio strings do stdin e quero exibir os usuários que correspondem às strings. O problema é que se o usuário inserir o caractere '[' ou uma string que o contenha.
grep -F
não funciona porque a linha tem que começar com a string (^ - que é um caractere simples com -F). Além disso, getent $user
não será bom porque preciso apenas do nome de usuário e não do ID também.
if [[ "$user" == *"["* ]]; then
echo -e "Invalid username.\n"
continue
fi
if ! getent passwd | grep "^$user:"; then
echo -e "Invalid username.\n"
continue
fi
Esta é a solução alternativa para '[', existe outra maneira?
awk
provavelmente fará o trabalho, mas ainda não tenho conhecimento disso, estou interessado em grep.
Responder1
Escape dele ou coloque-o em uma classe de personagem, algo assim:
grep '\['
grep '[[]'
grep -e "${user//\[/\\\[}"
A sintaxe ${var//c/d}
=> na variável shell $var
substituímos todos os caracteres c
por d
. Agora, no seu caso, é, c
mas [
acontece que [
é especial nesta sintaxe (faz globbing) e, portanto, precisamos escapá-lo prefixando-o com uma barra invertida, ou seja, \[
.
Agora chegando à peça de reposição, o que precisamos é de uma \[
peça ali. Mas, novamente, ambos \
e [
são especiais nesta sintaxe de ${var//...}
substituição de parâmetros e, portanto, ambos precisam ser, sim, você adivinhou certo, com barra invertida levando à expressão: \\\[
: "${var//\[/\\\[}"
HTH
Responder2
[
não é o único personagem a escapar para regexps. Todos os operadores RE estão incluindo .
o que é comum em nomes de usuário ( r.ot
como uma regexp corresponde, root
por exemplo).
Além disso, sua abordagem ( getent passwd | grep "^$user:"
) também é inválida porque não seria sinalizada root:0
como inválida, por exemplo.
Aqui, seria melhor usar awk
:
user_valid() {
getent passwd |
U="$1" awk -F: '$1 == ENVIRON["U"] {found = 1; exit}
END {exit(1 - found)}'
}
Agora, nem todos os bancos de dados de usuários permitem enumerações como essa.
$ getent passwd | grep stephane
$ id -u stephane
10631
$ getent passwd stephane
stephane:*:10631:10631:Stephane Chazelas:/export/./home/stephane:/bin/zsh
No meu caso, esse usuário está em um banco de dados LDAP.enumeraçãoestá desativado (pode haver milhares de usuários), mas ainda posso consultar/resolver usuários individualmente.
Então aqui, para validar usuários, é melhor consultar o banco de dados do usuário diretamente para esse usuário. Por exemplo, usando o id
comando (um comando padrão contrário a getent
):
user_valid() {
case $1 in
(*[!0-9]*) id -u -- "$1" > /dev/null 2>&1;;
(*) false;;
esac
}
(estamos cuidando de usuários com todos os dígitos separadamente, pois algumas id
implementações forneceriam informações para o ID do usuário nesse caso. Os nomes de usuário não podem ser numéricos na maioria dos sistemas (isso quebraria a maioria dos comandos que esperam nomes de usuário ou usuário ids como argumentos (como os id
acima, ps
, find
...))).
Responder3
Escapar de caracteres especiais é um pouco trabalhoso. Em vez disso, você pode simplesmente escolher primeiro o campo username da getent
saída de e depois comparar com a linha 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 strings fixas, -x
para correspondência de linha completa.
Se você não tiver usuários com nomes de usuário compostos apenas por dígitos, você poderá 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
Ou, para evitar problemas com getent
ou outros assumindo que uma sequência de dígitos deve ser um UID em vez de um nome de usuário, devemos chamargetpwnam()
manualmente. Isso não faz outras suposições sobre quais podem ser os nomes de usuário, além do que a getpwnam()
implementação subjacente faz.
export user
if ! perl -e 'exit !defined getpwnam($ENV{user})' ; then
echo "$user doesn't exist"
fi
Deixarei de escrever o wrapper C correspondente.