Wie kann ich alle Benutzernamen und / oder Home-Verzeichnisse auflisten?

16

Ich möchte alle Benutzerverzeichnisse auf dem Computer auflisten. Normalerweise mache ich Folgendes:

ls -l /home

Aber ich verwende es in einem Skript, das auf anderen Computern bereitgestellt wird, und vielleicht auf diesen Computern, die sie nicht als "Zuhause" bezeichnen (z. B. myHome). Also möchte ich es verallgemeinern ls -l ~. Es werden jedoch nur die Home-Verzeichnisse meiner Benutzer und nicht die Namen aller Home-Verzeichnisse der Benutzer aufgelistet (im Grunde möchte ich eine Liste der Benutzernamen auf dem Computer erhalten). Wie kann ich das verallgemeinern?

Lakerda
quelle
19
Es ist in der Tat, keine Garantie , dass alle Benutzer Home - Verzeichnisse sind Verzeichnisse von jedem eines Verzeichnis.
Hobbs
17
@hobbs oder dass sie sogar existieren, bis sich der Benutzer anmeldet. Dies ist eines dieser scheinbar einfachen Probleme, das sehr schnell komplex wird.
EightBitTony
11
Denken Sie daran, dass dies ~im Allgemeinen das Äquivalent von /home/user, nicht von /homeoder ist /home/*(was Ihrer Absicht näher zu sein scheint).
Ethan Kaminski
2
@EightBitTony: noch ... gibt es keine Garantie , dass das Home - Verzeichnis existiert überhaupt . Beispielsweise haben bei meiner Ubuntu-Installation mehrere Systembenutzer (einschließlich nobody) ihr Home-Verzeichnis auf festgelegt /nonexistent, was offensichtlich nicht vorhanden ist. (Für diese Benutzer ist natürlich auch der Kennwort-Hash *und die Shell auf /usr/sbin/nologinoder festgelegt /bin/false, sodass sie sich zunächst nicht im normalen Sinne anmelden können.)
Ilmari Karonen
1
Auf der anderen Seite kann ein (alter) NFS-Server Basisverzeichnisse für Benutzer bereitstellen, deren Name dem Betriebssystem nicht bekannt ist.
Rackandboneman

Antworten:

45

Viele Systeme haben einen getentBefehl zur Liste oder fragen Sie den Inhalt der Name Service - Datenbanken wie passwd, group, services, protocols...

getent passwd | cut -d: -f6

Würden Liste der Home - Verzeichnisse (die 6 th Kolon begrenzt Feld) alle Benutzer in Datenbanken, wird aufgezählt .

Der Benutzername selbst befindet sich im ersten Feld, also für die Liste der Benutzernamen:

getent passwd | cut -d: -f1

(Beachten Sie, dass diese Benutzer sich nicht beim System anmelden können oder dass ihr Basisverzeichnis erstellt wurde. Sie sind dem System jedoch bekannt und können in eine Benutzer-ID übersetzt werden.)

Bei Datenbanken, die nicht aufgelistet werden können, können Sie versuchen, jede mögliche Benutzer-ID einzeln abzufragen:

getent passwd {0..65535} | cut -d: -f1,6

(hier unter der Annahme, dass uids bei 65535 enden (einige Systeme unterstützen mehr) und eine Shell, die zshs {x..y}Form der Klammererweiterung unterstützt ). Auf Systemen, auf denen die Benutzerdatenbank vernetzt ist (und es nur begrenztes lokales Caching gibt), wie z. B. LDAP, NIS +, SQL ..., sollten Sie dies jedoch nicht häufig tun, da dies viel Netzwerkverkehr bedeuten und den Verzeichnisserver belasten kann ), um all diese Fragen zu stellen.

Das bedeutet auch, dass Sie nur einen Eintrag für jede Benutzer-ID erhalten, wenn mehrere Benutzer dieselbe Benutzer-ID verwenden. Verpassen Sie also die anderen.

Wenn Sie nicht haben getent, können Sie auf Folgendes zurückgreifen perl:

perl -le 'while (@e = getpwent) {print $e[7]}'

für getent passwd( $e[0]für die Benutzernamen) oder:

perl -le 'for ($i=0;$i<65536;++$i) {
  if (@e = getpwuid $i) {print $e[0] ": " $e[7]}}'

für getent passwd {0..65535}mit den gleichen einschränkungen.

In Shells können Sie das Basisverzeichnis ~uservon abrufen. In den usermeisten Shells funktioniert dies jedoch nur für einen begrenzten Satz von Benutzernamen (die Liste der zulässigen Zeichen in Benutzernamen, die für diesen ~Erweiterungsoperator unterstützt werden, variiert von Shell zu Shell) und mit Mehrere Shells (einschließlich bash) ~$userfunktionieren nicht (Sie müssten darauf zurückgreifeneval wenn der Name des Benutzers in einer Variablen dort gespeichert ist). Und Sie müssen noch einen Weg finden, um die Liste der Benutzernamen zu erhalten.

Einige Shells unterstützen diese Liste von Benutzernamen.

  • bash: compgen -uGibt die Liste der Benutzer in Datenbanken zurück, die aufgelistet werden können.
  • zsh: Das $userdirsassoziative Array ordnet Benutzernamen ihrem Ausgangsverzeichnis zu (auch beschränkt auf Datenbanken, die aufgelistet werden können. Wenn Sie jedoch eine ~userErweiterung für einen Benutzer vornehmen, der sich in einer nicht aufzählbaren Datenbank befindet, wird ein Eintrag hinzugefügt $userdirs). Sie können also Folgendes tun:

    printf '%s => %s\n' "${(kv@)userdirs}"

    um Benutzer mit ihrem Home-Verzeichnis aufzulisten.

    Das funktioniert aber nur, wenn zshes interaktiv ist .

  • tcsh, fishund yashsind drei weitere Shells, die Benutzernamen vervollständigen können (zum Beispiel beim Vervollständigen von ~<Tab>Argumenten), aber es sieht nicht so aus, als würden Sie diese Liste von Benutzernamen programmgesteuert erhalten.

Stéphane Chazelas
quelle
Die Herausforderung für das OP wird sein, zu wissen, ob getentes dort sein wird, was in gewissem Maße vom Umfang ihrer "anderen Maschinen" abhängt.
EightBitTony
1
@EightBitTony, ich habe eine perlAlternative hinzugefügt .
Stéphane Chazelas
1
Auf einem Mac ist dies wahrscheinlich ein Problem mit Open Directory.
SilverWolf - Setzen Sie Monica
@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'funktioniert gut unter macOS.
Stéphane Chazelas
1
@FloHe, das sind Benutzernamen. Die meisten Benutzer auf Unix-Systemen sind spezielle Systembenutzer, deren Leben dem Ausführen von Systemdiensten gewidmet ist. getent passwdzeigt Ihnen die Benutzerdatenbank. Das erste Feld ist der Benutzername, das sechste Feld ist das Ausgangsverzeichnis des Benutzers.
Stéphane Chazelas
17

Ein besserer Weg, um Benutzer-Home-Verzeichnisse aufzulisten, ist das Parsen /etc/passwd und von dort zu extrahieren und keine Vermutungen darüber anzustellen, wo sie sich befinden.

Und Ihrem zweiten Kommentar nach zu urteilen, möchten Sie eigentlich die Benutzernamen und nicht deren Home-Verzeichnisse. In diesem Fall /etc/passwdist dies ohnehin die bessere Wahl. Beachten Sie, dass auf einigen Linux- / UNIX-Computern andere Benutzerauthentifizierungsmechanismen konfiguriert sind (z. B. LDAP). Daher ist Ihre Abfrage letztendlich komplexer als Sie vielleicht zunächst glauben, aber /etc/passwdein guter Ausgangspunkt.

EightBitTony
quelle
9
Siehe auch getentSysteme, die dies unterstützen.
Kusalananda
6
Ja, getentist immer besser als das Parsen /etc/passwd(es geht um das Problem „anderer Benutzerauthentifizierungsmechanismen“).
Stephen Kitt
@Kusalananda Das Problem bei einer getentLösung ist, dass davon ausgegangen wird, dass die Datenquelle aufgezählt und nicht nur nach einem bestimmten Wert abgefragt werden kann. Das wird ausführlich in der Antwort von Stéphane Chazelas auf diese Frage beschrieben , aber ich würde trotzdem einen Kommentar für jeden hinzufügen, der über diese Seite blättert.
Andrew Henle
7

Die kurze Antwort :

compgen -u

Die mittlere Antwort : Da Sie verwenden bash, können Sie alle möglichen Abschlüsse für die ~Verwendung auflisten compgen -A user. Das ist so eine übliche Verwendung, es kann abgekürzt werden compgen -u. Hat als eingebaute Shell compgenkeine eigene Manpage. Lesen Sie stattdessen die Dokumentation in Bash (1) und den Abschnitt über die programmierbare Vervollständigung .

Eine gründlichere Alternative

Wenn Sie sich große Sorgen über die Portabilität machen, können Sie sich möglicherweise nicht einmal auf andere Computer verlassen bash. In diesem Fall machen Sie folgendes:

(getent passwd ||
    dscl . -ls /Users dsAttrTypeNative:homeDirectory || 
    nidump passwd  ||
    cat /etc/passwd) 2>/dev/null  |  cut -d: -f6

Erläuterung Die lange Antwort versucht alles, sodass sie auf so ziemlich jedem UNIX-System funktioniert, unabhängig davon, ob die neuere Datei /etc/nsswitch.conf (mit der sowohl GNU / Linux als auch BSD geliefert werden getent) verwendet wird, die traditionelle UNIX-Passwd-Flat-Datei (MacOS) Directory Services¹ ( dscl) oder sogar die älteren MacOS X-Versionen mit Cat-Thema und NeXTSTEP ( nidump).

Einfachheit Aber wie tragbar brauchen Sie? Unix hat viele Möglichkeiten, Dinge zu tun, und manchmal genügt einfacheres. Wenn Sie eine auswählen müssen, würde ich getent passwd | cut -d: -f6für Shell-Skripte empfehlen


Fußnote ¹: Ich habe MacOS schon länger nicht mehr benutzt. Wenn mir also jemand bestätigen kann, dass ich die richtige Syntax habe (und die Ausgabe keine Streukolons enthält, die das Ganze vermasseln würden cut), wäre das großartig. Vielen Dank.

Fußnote ²: Was ich empfehle und was ich tue, kann abweichen. Persönlich verwende ich häufiger die traditionelle cut -d: -f1 /etc/passwdBefehlszeile. Nach Jahrzehnten der Wiederholung können meine Finger es tippen, während mein Verstand an anderen Dingen arbeitet.

hackerb9
quelle
2
Auf allen Mac OS X-Rechnern ist Bash so gut wie garantiert, da es mit dem System geliefert wird. (Wie zsh und einige andere Shells.)
SilverWolf - Monica
Richtig, aber damals, als ich MacOS benutzte, hatte Apple Bash schon lange nicht mehr aktualisiert und es war eine verkrustete Version 3, die ich immer ersetzen musste. Hat Apple das Update von Bash verbessert?
Hackerb9
Siehe Warum versendet Apple Bash 3.2?
Stéphane Chazelas
Stimmt, habe nicht darüber nachgedacht. Meine Version von bash (macOS Sierra 10.12.6) ist 3.2.57. (:
SilverWolf - Setzen Sie Monica wieder ein
Sowieso bashhat compgen -useit 2.04 im Jahr 2000 veröffentlicht worden.
Stéphane Chazelas
2

Was ist ls -l ~/..? Hier werden alle Verzeichnisse im übergeordneten Verzeichnis Ihres Basisverzeichnisses aufgelistet.

MrMunch
quelle
4
Dies funktioniert nur auf Systemen, auf denen sich alle Basisverzeichnisse im selben Verzeichnis befinden, was nicht viele sind (Sie denken vielleicht, dass dies /homeauf Linux-Systemen üblich ist, aber was passiert, wenn Sie das als ausführen root?). Das Auflisten von Home-Verzeichnissen ist ein Abenteuer voller Fallstricke, wenn Sie alle Fälle behandeln möchten, auf die Sie wahrscheinlich stoßen. Weitere Informationen finden Sie in den anderen Antworten.
Stephen Kitt
7
Dies ist bis jetzt wohl die einzige Antwort, die OPs direkt beantwortet wahrgenommene Problem . Es beantwortet jedoch nicht das zugrunde liegende Problem von OP .
Pipe
1
Der Wert dieser Antwort besteht darin, zu verstehen, was sie vermisst und warum sie nicht so gut ist wie die anderen Antworten mit höherer Stimmenzahl.
Criggie