Như những người khác đã chỉ ra, grep
không phải là công cụ tốt nhất cho việc này. Nếu bạn khăng khăng sử dụng nó và nếu bạn grep
hỗ trợ -o
(chỉ in phần phù hợp của dòng) và -P
(sử dụng Biểu thức chính quy tương thích Perl), bạn có thể làm điều này:
$ grep -oP '^[^:]+|.*:\K[^:]+(?=:[^:]+)' /etc/password
terdon
/home/terdon
bob
/home/bob
Lưu ý rằng điều này sẽ in tất cả người dùng, bao gồm cả người dùng hệ thống. Tôi chỉ hiển thị 4 dòng làm ví dụ.
Điều đó sẽ in tên người dùng và thư mục nhà của tất cả người dùng nhưng trên các dòng riêng biệt. Sau đó, bạn cần nối từng cặp dòng để kết hợp chúng lại với nhau:
$ 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
Giải trình
Regex có hai phần, nó tìm kiếm ^[^:]+
OR (nghĩa là gì |
) .*:\K[^:]+(?=:[^:]+)
. Đầu tiên tìm kiếm một hoặc nhiều :
ký tự không phải từ đầu dòng. Điều này phù hợp với tên người dùng. Phần thứ hai tìm kiếm càng nhiều ký tự càng tốt cho đến khi một :
( .*:
) và sau đó loại bỏ chúng (đó là những gì \K
nó làm) để chúng không được in. Sau đó, nó khớp với một chuỗi không- :
được theo sau :
và không :
. Cấu (?=foo)
trúc này được gọi là giao diện tích cực và là cách khớp các ký tự sau một mẫu mà không bao gồm các ký tự đó trong chính khớp.
Các perl
lệnh sẽ thay thế dòng mới với :
và không gian nếu số dòng hiện tại ( $.
) chia hết cho 2. Vì vậy, mỗi dòng thứ hai.
/etc/passwd
có thể hoặc không thể là nơi tất cả người dùng đang ở. Cũng xem xétgetent passwd
.