Escape [no grep

Escape [no grep

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 -Fnão funciona porque a linha tem que começar com a string (^ - que é um caractere simples com -F). Além disso, getent $usernã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? awkprovavelmente 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 $varsubstituímos todos os caracteres cpor d. Agora, no seu caso, é, cmas [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.otcomo uma regexp corresponde, rootpor exemplo).

Além disso, sua abordagem ( getent passwd | grep "^$user:") também é inválida porque não seria sinalizada root:0como 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 idcomando (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 idimplementaçõ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 idacima, ps, find...))).

Responder3

Escapar de caracteres especiais é um pouco trabalhoso. Em vez disso, você pode simplesmente escolher primeiro o campo username da getentsaí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"

-Fpara strings fixas, -xpara 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 getentou 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.

informação relacionada