Comment lister tous les noms d'utilisateurs et / ou répertoires personnels?

16

Je veux lister tous les répertoires des utilisateurs sur la machine. Habituellement, je ferai:

ls -l /home

Mais je l'utilise dans un script qui sera déployé sur d'autres machines et peut-être que sur ces machines ils ne l'appellent pas à la maison (par exemple myHome). Je veux donc le généraliser ls -l ~. Mais il répertorie simplement les répertoires personnels de mes utilisateurs au lieu du nom de tous les répertoires personnels des utilisateurs (en gros, je veux obtenir une liste des noms d'utilisateurs sur la machine). Comment généraliser?

lakerda
la source
19
En fait, il n'y a aucune garantie que tous les répertoires personnels des utilisateurs sont des sous-répertoires d' un seul répertoire.
hobbs
17
@hobbs ou qu'ils existent même jusqu'à ce que l'utilisateur se connecte. C'est l'un de ces problèmes apparemment simples qui deviennent complexes très rapidement.
EightBitTony
11
Gardez à l'esprit que ~c'est généralement l'équivalent de /home/user, pas de /homeou /home/*(qui semble être plus proche de votre intention).
Ethan Kaminski
2
@EightBitTony: ... et il n'y a aucune garantie que le répertoire existe du tout . Par exemple, sur mon installation Ubuntu, plusieurs utilisateurs du système (y compris nobody) ont leur répertoire personnel défini sur /nonexistent, qui, évidemment, n'existe pas. (Bien sûr, ces utilisateurs ont également leur hachage de mot de passe défini sur *et leur shell défini sur /usr/sbin/nologinou /bin/false, donc ils ne peuvent vraiment pas se connecter dans le sens normal pour commencer.)
Ilmari Karonen
1
D'un autre côté, un serveur NFS (old school) peut servir des répertoires personnels pour des utilisateurs qui ne sont pas connus par leur système d'exploitation.
rackandboneman

Réponses:

45

De nombreux systèmes ont une getentcommande à la liste ou interroger le contenu des services Nom des bases de données comme passwd, group, services, protocols...

getent passwd | cut -d: -f6

Répertorierait les répertoires personnels (le champ délimité par le 6 e colon) de tous les utilisateurs des bases de données qui peuvent être énumérés .

Le nom d'utilisateur lui-même est dans le premier champ, donc pour la liste des noms d'utilisateurs:

getent passwd | cut -d: -f1

(notez que cela ne signifie pas que ces utilisateurs peuvent se connecter au système ou que leur répertoire personnel a été créé, mais qu'ils sont connus du système, ils peuvent être traduits en un ID utilisateur).

Pour les bases de données qui ne peuvent pas être énumérées, vous pouvez essayer et interroger chaque identifiant utilisateur possible individuellement:

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

(ici en supposant que les uids s'arrêtent à 65535 (certains systèmes prennent en charge plus) et un shell qui prend en charge la {x..y}forme d'expansion d'accolade de zsh ). Mais vous ne voudriez pas le faire souvent sur des systèmes où la base de données utilisateur est en réseau (et la mise en cache locale est limitée) comme LDAP, NIS +, SQL ... car cela pourrait impliquer beaucoup de trafic réseau (et charger sur le serveur d'annuaire) ) pour effectuer toutes ces requêtes.

Cela signifie également que si plusieurs utilisateurs partagent le même uid, vous n'aurez qu'une seule entrée pour chaque uid, alors manquez les autres.

Si vous n'en avez pas getent, vous pouvez recourir à perl:

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

pour getent passwd( $e[0]pour les noms d'utilisateur), ou:

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

pour getent passwd {0..65535}les mêmes mises en garde.

Dans les shells, vous pouvez utiliser ~userpour obtenir le répertoire personnel de user, mais dans la plupart des shells, cela ne fonctionne que pour un ensemble limité de noms d'utilisateurs (la liste des caractères autorisés dans les noms d'utilisateurs pris en charge pour cet ~opérateur d'expansion varie d'un shell à l'autre) et avec plusieurs shells (y compris bash), ~$userne fonctionneront pas (vous devrez y recourir evallorsque le nom de l'utilisateur est stocké dans une variable là-bas). Et il vous faudrait encore trouver un moyen d'obtenir la liste des noms d'utilisateurs.

Certains shells ont un support intégré pour obtenir cette liste de noms d'utilisateurs.

  • bash: compgen -uretournerait la liste des utilisateurs dans les bases de données qui peuvent être énumérées.
  • zsh: le $userdirstableau associatif mappe les noms d'utilisateurs à leur répertoire personnel (également limité aux bases de données qui peuvent être énumérées, mais si vous effectuez une ~userexpansion pour un utilisateur qui se trouve dans une base de données non énumérable, une entrée sera ajoutée à $userdirs). Vous pouvez donc faire:

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

    pour répertorier les utilisateurs avec leur répertoire personnel.

    Cela ne fonctionne que quand il zshest interactif .

  • tcsh, fishEt yashtrois autres coquilles qui peuvent compléter les noms d'utilisateur (par exemple lors de l' achèvement des ~<Tab>arguments), mais il ne semble pas qu'ils vous permettent d' obtenir cette liste des noms d'utilisateur par programme.

Stéphane Chazelas
la source
Le défi pour l'OP sera de savoir s'il getentva y avoir, ce qui, dans une certaine mesure, dépend de l'étendue de leurs «autres machines».
EightBitTony
1
@EightBitTony, j'ai ajouté une perlalternative.
Stéphane Chazelas
1
Sur Mac, c'est probablement quelque chose impliquant Open Directory.
SilverWolf
@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'fonctionne très bien sur macOS.
Stéphane Chazelas
1
@FloHe, ce sont des noms d'utilisateurs. La plupart des utilisateurs sur les systèmes Unix sont des utilisateurs système spéciaux dont la vie est dédiée à l'exécution des services système. getent passwdvous montre la base de données utilisateur. Le premier champ est le nom d'utilisateur, le 6ème est le répertoire personnel des utilisateurs.
Stéphane Chazelas
17

Une meilleure façon de répertorier les répertoires personnels des utilisateurs consiste à analyser /etc/passwd et de les extraire de là, et de ne faire aucune hypothèse sur leur emplacement.

Et à en juger par votre deuxième commentaire, vous voulez en fait que les noms d'utilisateurs, et non leurs répertoires personnels, dans ce cas, /etc/passwdsoient de toute façon un meilleur choix. Notez que certaines machines Linux / UNIX auront d'autres mécanismes d'authentification utilisateur configurés (par exemple LDAP), et donc en fin de compte, votre requête est plus complexe que vous ne l'imaginez, mais /etc/passwdc'est un bon point de départ.

EightBitTony
la source
9
Voir également getentsur les systèmes qui le prennent en charge.
Kusalananda
6
Oui, getentc'est toujours mieux que d'analyser /etc/passwd(cela répond au problème des «autres mécanismes d'authentification des utilisateurs»).
Stephen Kitt
@Kusalananda Le problème avec une getentsolution est qu'elle suppose que la source de données peut être énumérée, et pas seulement interrogée pour une valeur spécifique. C'est détaillé dans la réponse de Stéphane Chazelas à cette question , mais je pense que j'ajouterais un commentaire à toute personne survolant cette page.
Andrew Henle
7

La réponse courte :

compgen -u

La réponse moyenne : puisque vous utilisez bash, vous pouvez répertorier toutes les finitions possibles pour l' ~utilisation compgen -A user. C'est une telle utilisation courante, elle peut être abrégée compgen -u. En tant que shell intégré, compgenn'a pas sa propre page de manuel. Voir plutôt bash (1) pour la documentation et lire la section sur la complétion programmable .

Une alternative plus approfondie

Si vous êtes extrêmement préoccupé par la portabilité, vous ne pourrez peut-être même pas compter sur d'autres machines bash. Dans ce cas, procédez comme suit:

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

Explication La réponse longue essaie tout, donc cela fonctionnera sur à peu près n'importe quel système UNIX, indépendamment du fait qu'il utilise le plus récent /etc/nsswitch.conf (GNU / Linux et BSD sont fournis avec getent), le fichier plat passwd UNIX traditionnel, MacOS Directory Services¹ ( dscl), ou même les versions plus anciennes de MacOS X sur le thème des chats et NeXTSTEP ( nidump).

Simplicité Mais, comment avez-vous besoin de portable? Unix a plusieurs façons de faire les choses et suffit parfois plus simplement. Si vous devez en choisir un, je le recommanderais getent passwd | cut -d: -f6pour les scripts shell.²


Note de bas de page ¹: Je n'ai pas utilisé MacOS depuis un petit moment, donc si quelqu'un peut confirmer pour moi que j'ai la bonne syntaxe (et que la sortie n'inclut pas de deux-points errants qui gâcheraient cut), ce serait génial. Merci.

Note de bas de page ²: ce que je recommande et ce que je fais peut différer. Personnellement, j'utiliserai plus souvent le traditionnel cut -d: -f1 /etc/passwdsur la ligne de commande. Après des décennies de répétition, mes doigts peuvent taper pendant que mon esprit travaille sur d'autres choses.

hackerb9
la source
2
Toutes les machines Mac OS X sont à peu près garanties d'avoir bash, car elles sont fournies avec le système. (Tout comme zsh et plusieurs autres obus.)
SilverWolf - Réinstallez Monica
C'est vrai, mais à l'époque où j'utilisais MacOS, Apple n'avait pas mis à jour bash depuis longtemps et c'était quelque chose de version 3 croustillante que je devais toujours remplacer. Apple a-t-il amélioré la mise à jour de bash?
hackerb9
Voir Pourquoi Apple livre-t-il bash 3.2?
Stéphane Chazelas
C'est vrai, je n'y ai pas pensé. Ma version de bash (macOS Sierra 10.12.6) est 3.2.57. (:
SilverWolf
Quoi qu'il en soit, basha compgen -udepuis 2.04 sorti en 2000.
Stéphane Chazelas
2

Et alors ls -l ~/..? Ceci répertorie tous les répertoires dans le parent de votre répertoire personnel.

MrMunch
la source
4
Cela ne fonctionne que sur les systèmes où tous les répertoires personnels sont basés dans le même répertoire, ce qui n'est pas beaucoup (vous pourriez penser que /homec'est courant sur les systèmes Linux, mais que se passe-t-il lorsque vous exécutez cela en tant que root?). La liste des répertoires personnels est une aventure pleine d'embûches si vous voulez gérer tous les cas que vous rencontrerez probablement, voir les autres réponses pour plus de détails.
Stephen Kitt
7
C'est sans doute la seule réponse à ce jour qui réponde directement au problème perçu par OP . Cependant, cela ne répond pas au problème sous - jacent d'OP .
pipe
1
La valeur de cette réponse réside dans la compréhension de ce qui lui manque et pourquoi elle n'est pas aussi bonne que les autres réponses plus votées.
Criggie