Como outros apontaram, grep
não é a melhor ferramenta para isso. Se você insistir em usá-lo, e se o grep
suportar o -o
(apenas imprima a parte correspondente da linha) e -P
(use expressões regulares compatíveis com Perl), você pode fazer isso:
$ 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 mostrando apenas 4 linhas como exemplo.
Isso imprimirá o nome de usuário e os diretórios iniciais de todos os usuários, mas em linhas separadas. Você precisa então juntar 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
A regex tem duas partes, ela procura ^[^:]+
OR (é isso que o |
significa) .*:\K[^:]+(?=:[^:]+)
. O primeiro procura por um ou mais caracteres não- :
desde o início da linha. Isso corresponde ao nome do usuário. A segunda parte procura pelo maior número possível de caracteres até um :
( .*:
) e, em seguida, descarta-os (é o que faz o \K
) para que não sejam impressos. Em seguida, ele corresponde a uma sequência de caracteres não :
, seguida por :
e não :
. A construção (?=foo)
é chamada de lookahead positivo e é uma maneira de corresponder os caracteres após em um padrão sem incluir esses caracteres no próprio jogo.
O comando perl
substituirá as novas linhas com :
e espaços se o número da linha atual ( $.
) for divisível por 2. Assim, a cada segunda linha.