
Ich lese Zeichenfolgen von stdin und möchte die Benutzer anzeigen, die mit den Zeichenfolgen übereinstimmen. Das Problem besteht, wenn der Benutzer das Zeichen „[“ oder eine Zeichenfolge eingibt, die dieses enthält.
grep -F
funktioniert nicht, da die Zeile mit der Zeichenfolge (^ - was ein einfaches Zeichen mit -F ist) beginnen muss. getent $user
Wäre auch nicht gut, da ich nur den Benutzernamen und nicht die ID brauche.
if [[ "$user" == *"["* ]]; then
echo -e "Invalid username.\n"
continue
fi
if ! getent passwd | grep "^$user:"; then
echo -e "Invalid username.\n"
continue
fi
Dies ist die Problemumgehung für „[“. Gibt es eine andere Möglichkeit?
awk
Wird höchstwahrscheinlich funktionieren, aber ich weiß noch nichts darüber. Mich interessiert grep.
Antwort1
Entweder maskieren Sie es oder fügen es in eine Zeichenklasse ein, etwa so:
grep '\['
grep '[[]'
grep -e "${user//\[/\\\[}"
Die Syntax ${var//c/d}
=> in der Shell-Variable $var
ersetzen wir alle Zeichen c
durch d
. In Ihrem Fall c
ist das , [
aber es ist nun mal so, dass [
in dieser Syntax etwas Besonderes ist (es führt Globbing durch) und daher müssen wir es maskieren, indem wir ihm einen Backslash voranstellen, also \[
.
Kommen wir nun zum Ersetzungsteil. Was wir brauchen, ist ein \[
in. Aber nochmals, sowohl \
als auch [
sind in dieser Syntax der Parameterersetzung etwas Besonderes ${var//...}
und daher müssen beide, ja, Sie haben es richtig erraten, mit Backslashs versehen werden, was zu folgendem Ausdruck führt: \\\[
: "${var//\[/\\\[}"
HTH
Antwort2
[
ist nicht das einzige Zeichen, das bei regulären Ausdrücken maskiert wird. Alle RE-Operatoren sind inklusive, .
was bei Benutzernamen üblich ist ( z. B. r.ot
wenn ein regulärer Ausdruck übereinstimmt root
).
Darüber hinaus ist Ihr Ansatz ( ) auch insofern ungültig, als er beispielsweise getent passwd | grep "^$user:"
nicht als ungültig gekennzeichnet würde .root:0
Hier wäre es besser, Folgendes zu verwenden awk
:
user_valid() {
getent passwd |
U="$1" awk -F: '$1 == ENVIRON["U"] {found = 1; exit}
END {exit(1 - found)}'
}
Allerdings erlauben nicht alle Benutzerdatenbanken eine solche Aufzählung.
$ getent passwd | grep stephane
$ id -u stephane
10631
$ getent passwd stephane
stephane:*:10631:10631:Stephane Chazelas:/export/./home/stephane:/bin/zsh
In meinem Fall befindet sich dieser Benutzer in einer LDAP-Datenbank.Aufzählungist deaktiviert (es könnte Tausende von Benutzern geben), aber ich kann Benutzer immer noch einzeln abfragen/auflösen.
Um Benutzer zu validieren, ist es hier besser, die Benutzerdatenbank direkt nach diesem Benutzer abzufragen. Verwenden Sie beispielsweise den folgenden id
Befehl (im Gegensatz zu ein Standardbefehl getent
):
user_valid() {
case $1 in
(*[!0-9]*) id -u -- "$1" > /dev/null 2>&1;;
(*) false;;
esac
}
(Wir kümmern uns separat um Benutzer, die nur aus Ziffern bestehen, da einige id
Implementierungen Ihnen in diesem Fall Informationen zur Benutzer-ID geben würden. Benutzernamen können in den meisten Systemen nicht numerisch sein (das würde die meisten Befehle beschädigen, die entweder Benutzernamen oder Benutzer-IDs als Argumente erwarten (wie die id
oben stehenden s, ps
, find
...))).
Antwort3
Das Maskieren von Sonderzeichen ist etwas mühsam. Stattdessen können Sie getent
zunächst einfach das Feld username aus der Ausgabe von auswählen und dann mit der gesamten verbleibenden Zeile abgleichen:
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
für feste Zeichenfolgen, -x
für vollständige Zeilenübereinstimmung.
Wenn Sie keine Benutzer haben, deren Benutzernamen nur aus Ziffern bestehen, können Sie Folgendes verwenden 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
Oder, um die Probleme mit getent
oder anderen zu vermeiden, die annehmen, dass eine Ziffernfolge eine UID statt eines Benutzernamens sein muss, sollten wir anrufengetpwnam()
manuell. Dabei werden keine anderen Annahmen über die möglichen Benutzernamen getroffen als die, die die zugrunde liegende getpwnam()
Implementierung vornimmt.
export user
if ! perl -e 'exit !defined getpwnam($ENV{user})' ; then
echo "$user doesn't exist"
fi
Ich werde das Schreiben des entsprechenden C-Wrappers überspringen.