¿Cómo puedo enumerar todos los nombres de usuario y / o directorios de inicio?

16

Quiero enumerar todos los directorios de usuarios en la máquina. Por lo general, haré:

ls -l /home

Pero lo uso en un script que se implementará en otras máquinas y tal vez en esas máquinas no lo llaman hogar (por ejemplo, myHome). Entonces quiero generalizarlo ls -l ~. Pero solo enumera los directorios de inicio de mis usuarios en lugar del nombre de todos los directorios de inicio de los usuarios (básicamente quiero obtener una lista de los nombres de usuarios en la máquina). ¿Cómo puedo generalizarlo?

lakerda
fuente
19
De hecho, no hay garantía de que los directorios principales de todos los usuarios sean subdirectorios de ningún directorio.
hobbs
17
@hobbs o que existan hasta que el usuario inicie sesión. Este es uno de esos problemas aparentemente simples que se vuelve complejo muy rápido.
EightBitTony
11
Tenga en cuenta que ~generalmente es el equivalente de /home/user, no de /homeo /home/*(que parecen estar más cerca de su intención).
Ethan Kaminski
2
@EightBitTony: ... ni hay ninguna garantía de que existe el directorio principal en absoluto . Por ejemplo, en mi instalación de Ubuntu, varios usuarios del sistema (incluido nobody) tienen su directorio de inicio configurado en /nonexistent, que, obviamente, no existe. (Por supuesto, esos usuarios también tienen su hash de contraseña establecido en *y su shell establecido en /usr/sbin/nologino /bin/false, por lo que realmente no pueden iniciar sesión en el sentido normal para empezar).
Ilmari Karonen
1
Por otro lado, un servidor NFS (de la vieja escuela) podría servir directorios de inicio para usuarios que no son conocidos por su sistema operativo.
rackandboneman

Respuestas:

45

Muchos sistemas tienen un getentcomando a la lista o consultar el contenido de los Servicio de nombres de bases de datos como passwd, group, services, protocols...

getent passwd | cut -d: -f6

Sería una lista de los directorios de inicio (la 6 ª campo delimitado por dos puntos) de todos los usuarios de bases de datos que pueden ser enumerados .

El nombre de usuario en sí está en el primer campo, por lo que para la lista de nombres de usuario:

getent passwd | cut -d: -f1

(tenga en cuenta que no significa que esos usuarios puedan iniciar sesión en el sistema o que se haya creado su directorio de inicio, pero que el sistema los conoce, pueden traducirse a una identificación de usuario).

Para las bases de datos que no se pueden enumerar, puede intentar consultar cada ID de usuario posible individualmente:

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

(aquí suponiendo que los uids se detengan en 65535 (algunos sistemas admiten más) y un shell que admite la {x..y}forma de expansión de llaves de zsh ). Pero no querrá hacer eso a menudo en sistemas donde la base de datos de usuarios está en red (y hay un almacenamiento en caché local limitado) como LDAP, NIS +, SQL ... ya que eso podría implicar mucho tráfico de red (y cargar en el servidor de directorio) ) para hacer todas esas consultas.

Eso también significa que si hay varios usuarios que comparten el mismo uid, solo obtendrás una entrada para cada uid, así que echa de menos los demás.

Si no tiene getent, puede recurrir a perl:

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

para getent passwd( $e[0]para los nombres de usuario) o:

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

para getent passwd {0..65535} con las mismas advertencias.

En shells, puede usar ~userpara obtener el directorio de inicio de user, pero en la mayoría de los shells, eso solo funciona para un conjunto limitado de nombres de usuario (la lista de caracteres permitidos en los nombres de usuario admitidos para ese ~operador de expansión varía de un shell a otro) y con varias conchas (incluidas bash),~$user no funcionarán (necesitaría recurrir evalcuando el nombre del usuario se almacena en una variable allí). Y aún tendría que encontrar una manera de obtener la lista de nombres de usuario.

Algunos shells tienen soporte incorporado para obtener esa lista de nombres de usuario.

  • bash: compgen -u devolvería la lista de usuarios en bases de datos que se pueden enumerar.
  • zsh: la $userdirsmatriz asociativa asigna los nombres de usuario a su directorio de inicio (también limitado a las bases de datos que se pueden enumerar, pero si realiza una ~userexpansión para un usuario que se encuentra en una base de datos no enumerable, se agregará una entrada $userdirs). Entonces puedes hacer:

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

    para enumerar usuarios con su directorio de inicio.

    Sin zshembargo, eso solo funciona cuando es interactivo .

  • tcsh, fishy yashson otros tres shells que pueden completar nombres de usuario (por ejemplo, al completar ~<Tab>argumentos), pero no parece que le permitan obtener esa lista de nombres de usuario mediante programación.

Stéphane Chazelas
fuente
El desafío para el OP será saber si getentva a estar allí, lo que supongo que en cierta medida depende del alcance de sus 'otras máquinas'.
EightBitTony
1
@EightBitTony, he agregado una perlalternativa.
Stéphane Chazelas
1
En Mac, probablemente sea algo relacionado con Open Directory.
SilverWolf - Restablece a Mónica el
@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'funciona bien en macOS.
Stéphane Chazelas
1
@FloHe, esos son nombres de usuario. La mayoría de los usuarios en sistemas Unix son usuarios especiales del sistema cuya vida se dedica a ejecutar servicios del sistema. getent passwdle muestra la base de datos del usuario. El primer campo es el nombre de usuario, el sexto campo es el directorio de inicio de los usuarios.
Stéphane Chazelas
17

Una mejor manera de enumerar los directorios de inicio de los usuarios es analizarlos /etc/passwdy extraerlos desde allí, y no hacer suposiciones sobre dónde pueden estar.

Y a juzgar por su segundo comentario, realmente desea los nombres de usuario, no sus directorios de inicio, en cuyo caso, /etc/passwdes una mejor opción de todos modos. Tenga en cuenta que algunas máquinas Linux / UNIX tendrán otros mecanismos de autenticación de usuario configurados (por ejemplo, LDAP), por lo que, en última instancia, su consulta es más compleja de lo que podría imaginarse, pero /etc/passwdes un buen lugar para comenzar.

OchoBitTony
fuente
99
Consulte también los getentsistemas que lo admiten.
Kusalananda
66
Sí, getentsiempre es mejor que el análisis /etc/passwd(aborda la preocupación con "otros mecanismos de autenticación de usuario").
Stephen Kitt
@Kusalananda El problema con una getentsolución es que supone que la fuente de datos se puede enumerar, y no solo consultar por un valor específico. Eso se detalla en la respuesta de Stéphane Chazelas a esta pregunta , pero pensé que agregaría un comentario para cualquiera que lea esta página.
Andrew Henle
7

La respuesta corta :

compgen -u

La respuesta media : ya que está usando bash, puede enumerar todas las terminaciones posibles para ~usar compgen -A user. Ese es un uso tan común que se puede abreviar compgen -u. Como shell integrado, compgenno tiene su propia página de manual. En su lugar, consulte bash (1) para obtener documentación y lea la sección sobre Finalización programable .

Una alternativa más completa

Si está extremadamente preocupado por la portabilidad, es posible que ni siquiera pueda confiar en otras máquinas bash. En ese caso, haz esto:

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

Explicación La respuesta larga lo intenta todo, por lo que funcionará en casi cualquier sistema UNIX, independientemente de si utiliza el /etc/nsswitch.conf más reciente (tanto GNU / Linux como BSD vienen getent), el archivo plano tradicional UNIX passwd, MacOS Directory Services¹ ( dscl), o incluso las versiones anteriores de MacOS X con temas de gato y NeXTSTEP ( nidump).

Simplicidad Pero, ¿qué tan portátil necesitas? Unix tiene muchas formas de hacer las cosas y algunas veces es más simple. Si tiene que elegir uno, lo recomendaría getent passwd | cut -d: -f6para los scripts de shell .²


Nota: No he usado MacOS en un tiempo, así que si alguien puede confirmar por mí que tengo la sintaxis correcta (y la salida no incluye ningún punto perdido que pueda estropear cut), sería genial. Gracias.

Nota al pie ²: Lo que recomiendo y lo que hago puede diferir. Personalmente, usaré más a menudo el tradicional cut -d: -f1 /etc/passwden la línea de comando. Después de décadas de repetición, mis dedos pueden escribirlo mientras mi mente está trabajando en otras cosas.

hackerb9
fuente
2
Se garantiza que todas las máquinas Mac OS X tienen bash, ya que viene con el sistema. (Al igual que zsh y varios otros proyectiles.)
SilverWolf - Restablecer a Monica el
Es cierto, pero cuando estaba usando MacOS, Apple no había actualizado bash en mucho tiempo y era una cosa crujiente de la versión 3 que siempre tenía que reemplazar. ¿Apple ha mejorado sobre la actualización de bash?
hackerb9
Consulte ¿Por qué Apple envía bash 3.2?
Stéphane Chazelas
Es cierto, no pensé en eso. Mi versión de bash (macOS Sierra 10.12.6) es 3.2.57. (:
SilverWolf - Restablecer Monica
De todos modos, bashha tenido compgen -udesde 2.04 lanzado en 2000.
Stéphane Chazelas
2

¿Qué hay de ls -l ~/..? Esto enumera todos los directorios en el padre de su directorio de inicio.

MrMunch
fuente
44
Eso solo funciona en sistemas donde todos los directorios principales se basan en el mismo directorio, que no es mucho (podría pensar que /homees común en los sistemas Linux, pero ¿qué sucede cuando ejecuta eso como root?). Listado de directorios de inicio es una aventura llena de trampas si desea manejar todos los casos que probablemente encuentre, vea las otras respuestas para más detalles.
Stephen Kitt
77
Esta es posiblemente la única respuesta hasta ahora que responde directamente al problema percibido de OP . Sin embargo, no responde al problema subyacente de OP .
tubería
1
El valor de esta respuesta está en comprender lo que se pierde y por qué no es tan bueno como las otras respuestas con mayor voto.
Criggie