web-dev-qa-db-fra.com

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

Je veux lister tous les répertoires d'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 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?

16
lakerda

De nombreux systèmes ont une commande getent pour répertorier ou interroger le contenu des bases de données Name Service comme passwd, group, services, protocols...

getent passwd | cut -d: -f6

Répertorierait les répertoires personnels (le 6e champ délimité par deux-points) 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 le {x..y} forme de l'accolade). 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'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} avec les mêmes mises en garde.

Dans les shells, vous pouvez utiliser ~user pour 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 ce ~ L'opérateur d'expansion varie de Shell à Shell) et avec plusieurs shells (dont bash), ~$user ne fonctionnera pas (vous devrez recourir à eval lorsque le nom de l'utilisateur y est stocké dans une variable). 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 -u renverrait la liste des utilisateurs des bases de données qui peuvent être énumérés.
  • zsh: le $userdirs le tableau 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 un ~user expansion 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 lister les utilisateurs avec leur répertoire personnel.

    Cela ne fonctionne que lorsque zsh est interactif .

  • tcsh, fish et yash sont trois autres shells qui peuvent compléter les noms d'utilisateur (par exemple lorsque vous complétez ~<Tab> arguments), mais il ne semble pas qu'ils vous permettent d'obtenir cette liste de noms d'utilisateurs par programmation.

45
Stéphane Chazelas

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

Et à en juger par votre deuxième commentaire, vous voulez en fait les noms d'utilisateur, pas leurs répertoires personnels, auquel cas, /etc/passwd est 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/passwd est un bon point de départ.

17
EightBitTony

La réponse courte:

compgen -u

La réponse moyenne: Puisque vous utilisez bash, vous pouvez lister toutes les complétions possibles pour ~ en utilisant compgen -A user. C'est une telle utilisation courante, elle peut être abrégée compgen -u. En tant que module intégré de Shell, compgen n'a pas sa propre page de manuel. Voir à la place bash (1) pour la documentation et lire la section sur Achèvement programmable .

ne 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 ayant 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, qu'il utilise le plus récent /etc/nsswitch.conf (GNU/Linux et BSD sont livrés avec getent), le fichier plat passwd UNIX traditionnel, les services d'annuaire de MacOS¹ (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 recommanderais getent passwd | cut -d: -f6 pour les scripts Shell.²


Note de bas de page ¹: je n'ai pas utilisé MacOS depuis un 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 parasites 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/passwd sur la ligne de commande. Après des décennies de répétition, mes doigts peuvent le taper pendant que mon esprit travaille sur d'autres choses.

7
hackerb9

Qu'en est-il de ls -l ~/..? Ceci répertorie tous les répertoires du parent de votre répertoire personnel.

2
MrMunch