Làm thế nào tôi có thể liệt kê tất cả tên người dùng và / hoặc thư mục nhà?


16

Tôi muốn liệt kê tất cả các thư mục người dùng trên máy. Thông thường, tôi sẽ làm:

ls -l /home

Nhưng tôi sử dụng nó trong một tập lệnh sẽ được triển khai trên các máy khác và có thể trên các máy đó họ không gọi nó là nhà (ví dụ: myHome). Vì vậy, tôi muốn khái quát nó để ls -l ~. Nhưng nó chỉ liệt kê các thư mục nhà của người dùng của tôi thay vì tất cả tên thư mục nhà của người dùng (về cơ bản tôi muốn nhận danh sách tên người dùng trên máy). Làm thế nào tôi có thể khái quát nó?


19
Trên thực tế, không có gì đảm bảo rằng tất cả các thư mục nhà của người dùng là thư mục con của bất kỳ một thư mục nào .
hobbs

17
@hobbs hoặc chúng thậm chí tồn tại cho đến khi người dùng đăng nhập. Đây là một trong những vấn đề rõ ràng đơn giản trở nên phức tạp thực sự nhanh chóng.
EightBitTony

11
Hãy nhớ rằng ~nói chung là tương đương /home/user, không phải /homehoặc /home/*(dường như gần với ý định của bạn).
Ethan Kaminski

2
@EightBitTony: ... cũng không có gì đảm bảo rằng thư mục chính tồn tại cả . Ví dụ, trên bản cài đặt Ubuntu của tôi, một số người dùng hệ thống (bao gồm nobody) có thư mục chính của họ được đặt thành /nonexistent, rõ ràng là không tồn tại. (Tất nhiên, những người dùng cũng có thiết lập mật khẩu băm họ để *và bộ vỏ của mình để /usr/sbin/nologinhoặc /bin/false, vì vậy họ thực sự không thể đăng nhập theo nghĩa thông thường để bắt đầu với.)
Ilmari Karonen

1
Mặt khác, một máy chủ NFS (trường học cũ) có thể phục vụ các thư mục nhà cho những người dùng không biết tên hệ điều hành của nó.
rackandboneman

Câu trả lời:


45

Nhiều hệ thống có một getentlệnh vào danh sách hoặc truy vấn nội dung của Service Name cơ sở dữ liệu như passwd, group, services, protocols...

getent passwd | cut -d: -f6

Sẽ liệt kê các thư mục nhà ( trường phân cách dấu hai chấm thứ 6 ) của tất cả người dùng trong cơ sở dữ liệu có thể được liệt kê .

Tên người dùng nằm trong trường đầu tiên, vì vậy đối với danh sách tên người dùng:

getent passwd | cut -d: -f1

(lưu ý rằng điều đó không có nghĩa là những người dùng đó có thể đăng nhập vào hệ thống hoặc thư mục chính của họ đã được tạo, nhưng họ đã biết hệ thống, họ có thể được dịch sang id người dùng).

Đối với cơ sở dữ liệu không thể liệt kê, bạn có thể thử và truy vấn từng id người dùng có thể:

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

(ở đây giả sử uids dừng ở 65535 (một số hệ thống hỗ trợ nhiều hơn) và hệ vỏ hỗ trợ {x..y}hình thức mở rộng niềng răng của zsh ). Nhưng bạn sẽ không muốn làm điều đó thường xuyên trên các hệ thống mà cơ sở dữ liệu người dùng được nối mạng (và có bộ nhớ đệm cục bộ hạn chế) như LDAP, NIS +, SQL ... vì điều đó có thể ám chỉ rất nhiều lưu lượng mạng (và tải trên máy chủ thư mục ) để thực hiện tất cả các truy vấn đó.

Điều đó cũng có nghĩa là nếu có một vài người dùng chia sẻ cùng một uid, bạn sẽ chỉ nhận được một mục nhập cho mỗi uid, vì vậy hãy bỏ lỡ những người khác.

Nếu bạn không có getent, bạn có thể dùng đến perl:

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

cho getent passwd( $e[0]cho tên người dùng) hoặc:

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

cho getent passwd {0..65535}cùng hãy cẩn thận.

Trong shell, bạn có thể sử dụng ~userđể lấy thư mục chính của user, nhưng trong hầu hết các shell, chỉ hoạt động với một nhóm tên người dùng giới hạn (danh sách các ký tự được phép trong tên người dùng được hỗ trợ cho ~toán tử mở rộng khác nhau từ shell sang shell) và với một số shell (bao gồm bash), ~$usersẽ không hoạt động (bạn cần phải sử dụng evalkhi tên của người dùng được lưu trữ trong một biến ở đó). Và bạn vẫn phải tìm cách lấy danh sách tên người dùng.

Một số shell có hỗ trợ dựng sẵn để có được danh sách tên người dùng đó.

  • bash: compgen -usẽ trả về danh sách người dùng trong cơ sở dữ liệu có thể được liệt kê.
  • zsh: $userdirsmảng kết hợp ánh xạ tên người dùng vào thư mục chính của họ (cũng giới hạn ở cơ sở dữ liệu có thể được liệt kê, nhưng nếu bạn ~usermở rộng cho người dùng trong cơ sở dữ liệu không thể đếm được, một mục nhập sẽ được thêm vào $userdirs). Vì vậy, bạn có thể làm:

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

    để liệt kê người dùng với thư mục nhà của họ.

    Điều đó chỉ hoạt động khi zshđược tương tác mặc dù .

  • tcsh, fishyashba vỏ khác có thể hoàn thành tên người dùng (ví dụ khi hoàn thành ~<Tab>luận), nhưng nó không giống như họ để cho bạn có được rằng danh sách các tên người dùng lập trình.


Thách thức đối với OP sẽ là biết liệu getentsẽ có ở đó hay không, điều mà tôi đoán ở một mức độ nào đó phụ thuộc vào phạm vi của 'các máy khác' của họ.
EightBitTony

1
@EightBitTony, tôi đã thêm một giải perlpháp thay thế.
Stéphane Chazelas

1
Trên Mac, nó có lẽ là một cái gì đó liên quan đến Thư mục mở.
SilverWolf - Phục hồi Monica

@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'hoạt động tốt trên macOS.
Stéphane Chazelas

1
@FloHe, đó là những tên người dùng. Hầu hết người dùng trên các hệ thống Unix là những người dùng hệ thống đặc biệt có cuộc sống dành riêng cho việc chạy các dịch vụ hệ thống. getent passwdhiển thị cho bạn cơ sở dữ liệu người dùng. Trường đầu tiên là tên người dùng, trường thứ 6 là thư mục nhà của người dùng.
Stéphane Chazelas

17

Một cách tốt hơn để liệt kê các thư mục nhà của người dùng, là phân tích /etc/passwdvà trích xuất chúng từ đó, và không đưa ra bất kỳ giả định nào về nơi chúng có thể.

Và đánh giá bằng nhận xét thứ hai của bạn, bạn thực sự muốn tên người dùng, không phải thư mục chính của họ, trong trường hợp đó, /etc/passwdlà một lựa chọn tốt hơn dù sao đi nữa. Lưu ý rằng một số máy Linux / UNIX sẽ có các cơ chế xác thực người dùng khác được định cấu hình (ví dụ: LDAP) và do đó, cuối cùng, truy vấn của bạn phức tạp hơn bạn tưởng tượng trước đây, nhưng /etc/passwdlà một nơi tốt để bắt đầu.


9
Xem thêm getenttrên các hệ thống hỗ trợ nó.
Kusalananda

6
Có, getentluôn luôn tốt hơn so với phân tích cú pháp /etc/passwd(nó giải quyết mối quan tâm với các cơ chế xác thực người dùng khác khác).
Stephen Kitt

@Kusalananda Vấn đề với một getentgiải pháp là nó giả sử nguồn dữ liệu có thể được liệt kê và không chỉ truy vấn cho một giá trị cụ thể. Đó là chi tiết trong câu trả lời của Stéphane Chazelas cho câu hỏi này , nhưng tôi mặc dù tôi muốn thêm một nhận xét cho bất kỳ ai lướt qua trang này.
Andrew Henle

7

Câu trả lời ngắn gọn :

compgen -u

Câu trả lời trung bình : Vì bạn đang sử dụng bash, bạn có thể liệt kê tất cả các lần hoàn thành có thể để ~sử dụng compgen -A user. Đó là một cách sử dụng phổ biến, nó có thể được viết tắt compgen -u. Là một vỏ dựng sẵn, compgenkhông có trang người đàn ông của riêng mình. Thay vào đó, xem bash (1) để biết tài liệu và đọc phần về Hoàn thành lập trình .

Một sự thay thế kỹ lưỡng hơn

Nếu bạn cực kỳ lo lắng về tính di động, bạn thậm chí không thể dựa vào các máy khác có bash. Trong trường hợp đó, hãy làm điều này:

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

Giải thích Câu trả lời dài thử mọi thứ, vì vậy nó sẽ hoạt động trên hầu hết mọi hệ thống UNIX, bất kể nó có sử dụng /etc/nsswitch.conf mới (cả GNU / Linux và BSD đi kèm getent), tệp phẳng truyền thống UNIX, MacOS Directory Services¹ ( dscl), hoặc thậm chí các phiên bản MacOS X có chủ đề cũ hơn dành cho mèo và NeXTSTEP ( nidump).

Đơn giản Nhưng, bạn cần di động như thế nào? Unix có nhiều cách để làm mọi thứ và đôi khi đủ đơn giản hơn. Nếu bạn phải chọn một, tôi khuyên bạn nên getent passwd | cut -d: -f6dùng shell scripts.²


Chú thích ¹: Tôi đã không sử dụng MacOS một chút, vì vậy nếu ai đó có thể xác nhận cho tôi rằng tôi đã hiểu đúng cú pháp (và đầu ra không bao gồm bất kỳ dấu hai chấm nào sẽ gây rối cut), điều đó thật tuyệt. Cảm ơn.

Chú thích ²: Những gì tôi đề xuất và những gì tôi làm có thể khác nhau. Cá nhân, tôi sẽ thường xuyên sử dụng truyền thống cut -d: -f1 /etc/passwdtại dòng lệnh. Sau nhiều thập kỷ lặp đi lặp lại, ngón tay của tôi có thể gõ nó trong khi tâm trí tôi đang làm việc với những thứ khác.


2
Tất cả các máy Mac OS X đều được bảo đảm khá nhiều, vì nó đi kèm với hệ thống. (Cũng như zsh và một số vỏ khác.)
SilverWolf - Tái lập Monica

Đúng như vậy, nhưng trở lại khi tôi đang sử dụng MacOS, Apple đã không cập nhật bash trong một thời gian dài và đó là một số phiên bản 3 khó chịu mà tôi luôn phải thay thế. Apple đã nhận được tốt hơn về việc cập nhật bash?
hackerb9


Đúng, không nghĩ về điều đó. Phiên bản bash của tôi (macOS Sierra 10.12.6) là 3.2.57. (:
SilverWolf - Phục hồi Monica

Dù sao, bashđã có compgen -utừ 2.04 được phát hành vào năm 2000.
Stéphane Chazelas

2

Thế còn ls -l ~/..? Điều này liệt kê tất cả các thư mục trong cha mẹ của thư mục nhà của bạn.


4
Điều đó chỉ hoạt động trên các hệ thống mà tất cả các thư mục nhà đều dựa trên cùng một thư mục, điều này không nhiều (bạn có thể nghĩ /homelà phổ biến trên các hệ thống Linux, nhưng điều gì xảy ra khi bạn chạy như rootvậy?). Danh sách các thư mục nhà là một cuộc phiêu lưu đầy cạm bẫy nếu bạn muốn xử lý tất cả các trường hợp bạn có thể gặp phải, xem các câu trả lời khác để biết chi tiết.
Stephen Kitt

7
Đây được cho là câu trả lời duy nhất cho đến nay trực tiếp trả lời vấn đề nhận thức của OP . Tuy nhiên, nó không trả lời vấn đề cơ bản của OP .
ống

1
Giá trị trong câu trả lời này là trong việc hiểu những gì nó bỏ lỡ, và tại sao nó không tốt như các câu trả lời được bình chọn cao hơn khác.
Criggie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.