Como outros já apontaram, grep
não é a melhor ferramenta para isso. Se você insistir em usá-lo, e se você grep
suporta -o
(imprima apenas a parte correspondente da linha) e -P
(use Expressões Regulares Compatíveis com Perl), faça o seguinte:
$ grep -oP '^[^:]+|.*:\K[^:]+(?=:[^:]+)' /etc/password
terdon
/home/terdon
bob
/home/bob
Observe que isso imprimirá todos os usuários, incluindo os usuários do sistema. Estou apenas mostrando 4 linhas como exemplo.
Isso imprimirá o nome do usuário e os diretórios pessoais de todos os usuários, mas em linhas separadas. Você precisa unir cada par de linhas para juntá-las:
$ grep -oP '^[^:]+|.*:\K[^:]+(?=:[^:]+)' /etc/passwd | perl -pe 's/\n/ : / if $.%2'
root : /root
bin : /bin
daemon : /
mail : /var/spool/mail
ftp : /srv/ftp
http : /srv/http
uuidd : /
dbus : /
nobody : /
systemd-journal-gateway : /
systemd-timesync : /
systemd-network : /
systemd-bus-proxy : /
systemd-resolve : /
systemd-journal-upload : /
systemd-coredump : /
systemd-journal-remote : /
terdon : /home/terdon
avahi : /
polkitd : /
colord : /var/lib/colord
rtkit : /proc
gdm : /var/lib/gdm
git : /
bob : /home/bob
Explicação
O regex tem duas partes: procura ^[^:]+
OR (é isso que |
significa) .*:\K[^:]+(?=:[^:]+)
. O primeiro procura por um ou mais não :
caracteres desde o início da linha. Isso corresponde ao nome do usuário. A segunda parte procura o máximo de caracteres possível até a :
( .*:
) e os descarta (é o que \K
faz) para que não sejam impressos. Em seguida, corresponde a uma sequência de não - :
que é seguida por :
e não - :
. A (?=foo)
construção é chamada de aparência positiva e é uma maneira de corresponder os caracteres após um padrão sem incluir esses caracteres na própria correspondência.
O perl
comando substituirá as novas linhas por :
e espaços se o número da linha atual ( $.
) for divisível por 2. Portanto, a cada segunda linha.
/etc/passwd
pode ou não estar onde estão todos os usuários. Considere tambémgetent passwd
.