Como posso listar todos os nomes de usuário e / ou diretórios pessoais?

16

Quero listar todos os diretórios de usuários na máquina. Geralmente, farei:

ls -l /home

Mas eu o uso em um script que será implantado em outras máquinas e talvez nas máquinas que eles não chamam de lar (por exemplo, myHome). Então, eu quero generalizar isso ls -l ~. Mas apenas lista os diretórios pessoais dos usuários em vez do nome de todos os usuários domésticos (basicamente quero obter uma lista dos nomes dos usuários na máquina). Como posso generalizá-lo?

Lakerda
fonte
19
De fato, não há garantia de que todos os diretórios pessoais de usuários sejam subdiretórios de qualquer diretório.
Hbbs #
17
@ Hobbs ou que eles até existam até o usuário efetuar login. Esse é um daqueles problemas aparentemente simples que se tornam complexos muito rapidamente.
EightBitTony
11
Lembre-se de que ~geralmente é o equivalente de /home/user, não de /homeou /home/*(que parece estar mais próximo de sua intenção).
Ethan Kaminski
2
@EightBitTony: ... nem há qualquer garantia de que o diretório pessoal existe em tudo . Por exemplo, na minha instalação do Ubuntu, vários usuários do sistema (incluindo nobody) têm seu diretório pessoal definido como /nonexistent, o que, obviamente, não existe. (Claro, os usuários também têm o seu conjunto de hash de senha para *e seu conjunto de shell para /usr/sbin/nologinou /bin/false, então eles realmente não pode logar-se no sentido normal para começar.)
Ilmari Karonen
11
Por outro lado, um servidor NFS (da velha escola) pode servir diretórios pessoais para usuários que não são conhecidos pelo nome em seu sistema operacional.
rackandboneman

Respostas:

45

Muitos sistemas têm um getentcomando à lista ou consultar o conteúdo dos Name Service bases de dados como passwd, group, services, protocols...

getent passwd | cut -d: -f6

Listaria os diretórios pessoais (o 6 ° campo delimitado por dois pontos) de todos os usuários nos bancos de dados que podem ser enumerados .

O nome do usuário está no primeiro campo, portanto, para a lista de nomes de usuário:

getent passwd | cut -d: -f1

(observe que isso não significa que esses usuários podem efetuar login no sistema ou que seu diretório pessoal foi criado, mas que eles são conhecidos pelo sistema, podem ser traduzidos para um ID do usuário).

Para bancos de dados que não podem ser enumerados, você pode tentar consultar cada ID de usuário possível individualmente:

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

(assumindo que os uids param em 65535 (alguns sistemas suportam mais) e um shell que suporta a {x..y}forma de expansão de chaves do zsh ). Mas você não gostaria de fazer isso frequentemente em sistemas em que o banco de dados do usuário está em rede (e há cache local limitado) como LDAP, NIS +, SQL ... pois isso pode implicar muito tráfego de rede (e carregar no servidor de diretório ) para fazer todas essas consultas.

Isso também significa que, se houver vários usuários compartilhando o mesmo uid, você receberá apenas uma entrada para cada uid; portanto, perca os outros.

Se você não possui getent, pode recorrer a perl:

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

para getent passwd( $e[0]para os nomes de usuário) ou:

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

para getent passwd {0..65535}com as mesmas ressalvas.

Nos shells, você pode usar ~userpara obter o diretório inicial de user, mas na maioria dos shells, isso funciona apenas para um conjunto limitado de nomes de usuários (a lista de caracteres permitidos nos nomes de usuários suportados pelo ~operador de expansão varia de shell para shell) e com vários shells (inclusive bash), ~$usernão funcionarão (você precisará recorrer evalquando o nome do usuário estiver armazenado em uma variável). E você ainda teria que encontrar uma maneira de obter a lista de nomes de usuário.

Alguns shells têm suporte embutido para obter essa lista de nomes de usuários.

  • bash: compgen -uretornaria a lista de usuários em bancos de dados que podem ser enumerados.
  • zsh: a $userdirsmatriz associativa mapeia os nomes de usuários para o diretório inicial (também limitado aos bancos de dados que podem ser enumerados, mas se você fizer uma ~userexpansão para um usuário que esteja em um banco de dados não enumerável, uma entrada será adicionada $userdirs). Então você pode fazer:

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

    para listar usuários com seu diretório inicial.

    Isso só funciona quando zshé interativo .

  • tcsh, fishe yashsão três outros shells que podem completar nomes de usuário (por exemplo, ao concluir ~<Tab>argumentos), mas não parece que eles permitem obter essa lista de nomes de usuário programaticamente.

Stéphane Chazelas
fonte
O desafio para o OP será saber se getentele estará lá, o que eu acho que até certo ponto depende do escopo de suas 'outras máquinas'.
precisa
11
@EightBitTony, adicionei uma perlalternativa.
Stéphane Chazelas
11
No Mac, é provavelmente algo que envolve o Open Directory.
SilverWolf - Restabelece Monica
@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'funciona bem no macOS.
Stéphane Chazelas
11
@ FloHe, esses são nomes de usuário. A maioria dos usuários dos sistemas Unix são usuários especiais do sistema cuja vida é dedicada à execução dos serviços do sistema. getent passwdmostra o banco de dados do usuário. O primeiro campo é o nome do usuário, o sexto campo é o diretório inicial do usuário.
Stéphane Chazelas
17

Uma maneira melhor de listar os diretórios pessoais dos usuários é analisá /etc/passwd-los e extraí-los a partir daí, e não fazer nenhuma suposição sobre onde eles podem estar.

E, a julgar pelo seu segundo comentário, você realmente deseja os nomes de usuário, e não os diretórios pessoais, nesse caso, /etc/passwdé uma opção melhor de qualquer maneira. Observe que algumas máquinas Linux / UNIX terão outros mecanismos de autenticação de usuário configurados (por exemplo, LDAP) e, portanto, sua consulta é mais complexa do que você imagina, mas /etc/passwdé um bom ponto de partida.

EightBitTony
fonte
9
Veja também getentem sistemas que o suportam.
Kusalananda
6
Sim, getenté sempre melhor do que analisar /etc/passwd(trata da preocupação com "outros mecanismos de autenticação de usuário").
Stephen Kitt
@Kusalananda O problema de uma getentsolução é que ela pressupõe que a fonte de dados possa ser enumerada e não apenas consultada por um valor específico. Isso está detalhado na resposta de Stéphane Chazelas a esta pergunta , mas eu gostaria de adicionar um comentário para qualquer um que folhear esta página.
Andrew Henle
7

A resposta curta :

compgen -u

A resposta média : como você está usando bash, é possível listar todas as conclusões possíveis para ~usarcompgen -A user . Esse é um uso tão comum que pode ser abreviado compgen -u. Como um shell embutido, compgennão possui sua própria página de manual. Em vez disso, consulte o bash (1) para obter a documentação e leia a seção Conclusão programável .

Uma alternativa mais completa

Se você está extremamente preocupado com a portabilidade, talvez nem consiga confiar em outras máquinas bash. Nesse caso, faça o seguinte:

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

Explicação A resposta longa tenta de tudo, por isso funcionará em praticamente qualquer sistema UNIX, independentemente de usar o /etc/nsswitch.conf mais recente (ambos vêm com o GNU / Linux e o BSD getent), o tradicional arquivo simples de senha do UNIX, o MacOS Directory Services¹ ( dscl), ou mesmo versões mais antigas do MacOS X com tema de gato e NeXTSTEP ( nidump).

Simplicidade Mas, quão portátil você precisa? O Unix tem muitas maneiras de fazer as coisas e às vezes é mais simples. Se você precisar escolher um, eu recomendaria getent passwd | cut -d: -f6para scripts de shell.²


Nota de rodapé ¹: eu não uso o MacOS há um tempo, portanto, se alguém puder confirmar para mim que eu tenho a sintaxe correta (e a saída não inclui nenhum cólon perdido que estragaria cut), isso seria ótimo. Obrigado.

Nota de rodapé²: O que eu recomendo e o que faço pode ser diferente. Pessoalmente, usarei mais frequentemente o tradicional cut -d: -f1 /etc/passwdna linha de comando. Depois de décadas de repetição, meus dedos podem digitar enquanto minha mente está trabalhando em outras coisas.

hackerb9
fonte
2
Todas as máquinas Mac OS X têm praticamente a garantia de que o bash é fornecido com o sistema. (Como o zsh e várias outras conchas.)
SilverWolf - Restabelece Monica
É verdade, mas quando eu estava usando o MacOS, a Apple não atualizava o bash há muito tempo e era uma coisa difícil da versão 3 que eu sempre tinha que substituir. A Apple ficou melhor com a atualização do bash?
precisa saber é o seguinte
Consulte Por que a Apple envia o bash 3.2?
Stéphane Chazelas
Verdade, não pensei nisso. Minha versão do bash (macOS Sierra 10.12.6) é 3.2.57. (:
SilverWolf - Reinstate Monica
De qualquer forma, bashteve compgen -udesde 2.04 lançado em 2000.
Stéphane Chazelas
2

Que tal ls -l ~/..? Isso lista todos os diretórios no pai do seu diretório pessoal.

MrMunch
fonte
4
Isso funciona apenas em sistemas em que todos os diretórios pessoais são baseados no mesmo diretório, o que não é muito (você pode pensar que /homeé comum nos sistemas Linux, mas o que acontece quando você executa isso como root?). Listar diretórios pessoais é uma aventura cheia de armadilhas, se você quiser lidar com todos os casos que provavelmente encontrará, consulte as outras respostas para obter detalhes.
Stephen Kitt
7
Esta é sem dúvida a única resposta até agora que responde diretamente ao problema percebido do OP . No entanto, ele não responde ao problema subjacente do OP .
pipe
11
O valor desta resposta está em entender o que falta e por que não é tão bom quanto as outras respostas com maior número de votos.
Crygie # 8/17