Liệt kê tất cả người dùng


19

Làm cách nào tôi có thể liệt kê tất cả người dùng mà tôi đã tạo? Tôi đã thử cat /etc/passwdvà nó chỉ liệt kê rất nhiều thứ.

Câu trả lời:


18

Người dùng con người có UID bắt đầu từ 1000, vì vậy bạn có thể sử dụng thực tế đó để lọc ra những người không phải là con người:

cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1

Thao tác này sẽ cắt các trường được phân tách bằng dấu hai chấm (tên người dùng) và thứ ba (UID) /etc/passwd, sau đó lọc các dòng kết quả kết thúc bằng dấu hai chấm và bốn chữ số, sau đó cắt trường (tên người dùng) đầu tiên từ đó, để lại cho bạn một danh sách người dùng có UID trong khoảng từ 1000 đến 9999.

Nếu bạn có hơn chín nghìn người dùng trên hệ thống của mình, điều này sẽ thất bại - nhưng cần hạn chế kết quả đối với UID 4 chữ số để không bắt nobody(UID 65534).


15

Điều này thực hiện khá nhiều những gì câu trả lời được chấp nhận làm, chỉ trong một lệnh thay vì ba:

awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd

Và nhờ Karel trong các bình luận, nobodyngười dùng cũng được lọc ra.


@karel Vâng, có thể. Thay vì lọc theo UID, tôi lọc rõ tên người dùng đó. Có thể có một lý do để có một người dùng hợp pháp với UID cao đến mức ... Ai biết được;)
Oli

9

Cá nhân tôi chỉ thích sử dụng:

ls /home

Phải thừa nhận rằng đây không phải là danh sách người dùng mà thay vào đó là danh sách các thư mục nhà của họ. Hiện tại người dùng hiện tại trên hệ thống sẽ có thư mục chính trong/home , nhưng bạn cũng có thể thấy các thư mục chính của những người dùng trước đây đã bị xóa.

Điều này hoạt động cho mục đích của tôi và cũng có thể làm việc cho bạn. Ví dụ: nếu bạn đang tìm cách xóa tài khoản người dùng hóa ra không còn tồn tại ( nonexistent-user) và chạy lệnh

sudo deluser nonexistent-user

nó sẽ chỉ cho bạn biết rằng người dùng này không tồn tại.


+1 Cách này rất đơn giản, đó là điều mà hầu hết người dùng có kinh nghiệm thực sự sẽ làm và tôi nghĩ nó không kém phần mạnh mẽ so với các phương pháp kiểm tra một loạt UID. Dường như người dùng con người sẽ có một thư mục chính bên ngoài /home(không liên kết với nhau /home) so với người dùng con người sẽ có UID dưới 1000 (xét cho cùng, đây là phương pháp phổ biến nhất để giữ trình quản lý hiển thị khỏi danh sách một người dùng trên màn hình đăng nhập, đôi khi có thể được thực hiện cho người dùng con người). Một nhược điểm tương đối nhỏ ở đây là lost+foundsẽ được liệt kê trên các hệ thống có /homephân vùng riêng .
Eliah Kagan

Tuy nhiên, vấn đề nhỏ: điều gì xảy ra nếu người dùng được tạo bằng useradd --no-create-home username?
Sergiy Kolodyazhnyy

@Serg Tôi nghĩ rằng nó đi xuống sự mơ hồ vốn có trong mô tả vấn đề. Liệu một tài khoản không có thư mục chính thực sự đại diện cho một người dùng? Trong thực tế, các tài khoản như vậy thường - mặc dù không phải lúc nào cũng được sử dụng cho các tác vụ chuyên môn cao (thường là bởi những người có tài khoản riêng) hoặc cho người dùng chỉ truy cập hệ thống thông qua các dịch vụ cụ thể, bị hạn chế. Tất nhiên, có một trường hợp sử dụng khác cho useradd --no-create-home- thư mục chính có thể đã tồn tại hoặc có thể được tạo ngay sau đó - nhưng ls /homephương thức này hoạt động tốt cho những trường hợp đó.
Eliah Kagan

4

Mặc dù nó có vẻ như là một ý tưởng rõ ràng, nhưng thực sự có sự mơ hồ trong ý nghĩa của người dùng . Là một tài khoản người dùng cố tình bị ẩn khỏi màn hình đăng nhập vì nó chỉ được sử dụng cho các mục đích chuyên biệt (nhưng bởi con người) là người dùng? Còn ubuntungười dùng (UID 999) trên CD trực tiếp thì sao? Và các tài khoản khách trong Ubuntu được tạo nhanh chóng và bị hủy sau khi đăng xuất; Họ có phải là người dùng không? Nhiều ví dụ có thể được nghĩ ra.

Do đó, thật phù hợp khi nhiều câu trả lời không tương đương đã được đưa ra. Giải pháp chạy bộ của Saige Hamblinls /home là những gì mọi người thực sự làm, và trừ khi bạn viết một kịch bản, có lẽ bạn chỉ nên sử dụng nó.

Làm cho ls /homemạnh mẽ hơn

Nhưng có lẽ bạn có người dùng đã bị xóa nhưng thư mục nhà vẫn còn tồn tại /homevà bạn phải tránh liệt kê chúng. Hoặc có thể vì một số lý do khác, bạn phải đảm bảo chỉ các mục trong/home đó tương ứng với các tài khoản thực được liệt kê.

Trong trường hợp đó, tôi khuyên bạn nên đi qua các tên của tất cả mọi thứ trong /homeđể getent(để lấy passwdmục của người dùng với những cái tên đó), sau đó cô lập và hiển thị chỉ là lĩnh vực tên người dùng (với grep, sedhoặc awk, theo sở thích của bạn). Bất kỳ một trong số này sẽ làm:

getent passwd $(ls /home) | grep -o '^[^:]*'
getent passwd $(ls /home) | sed 's/:.*//'
getent passwd $(ls /home) | awk -F: '{print $1}'

Điều này sẽ hoạt động tốt, vì bạn không nên có tài khoản người dùng có khoảng trắng hoặc ký tự điều khiển trong tên của họ; không thể, mà không cấu hình lại Ubuntu để cho phép nó ; và nếu bạn làm, bạn có vấn đề lớn hơn. Do đó, các vấn đề thông thường với phân tích cú pháp ls không thể áp dụng. Nhưng ngay cả khi nó thực sự ổn ở đây, nếu bạn xem xét việc thay thế lệnh bằng phương pháp lsthẩm mỹ hoặc chỉ là một thói quen xấu, bạn có thể thích:

getent passwd $(basename -a /home/*) | grep -o '^[^:]*'
getent passwd $(basename -a /home/*) | sed 's/:.*//'
getent passwd $(basename -a /home/*) | awk -F: '{print $1}'

Chúng không chứa khoảng trắng hoặc ký tự điều khiển. Tôi cung cấp cho họ chỉ vì $(ls /home)trông sai ngay cả khi nó đúng, và do đó chà xát nhiều người dùng sai cách. Trong hầu hết các tình huống, có những lý do thực tế, tốt để tránh phân tích cú phápls và trong những tình huống đó, phân tích cú pháp basename -athường chỉ kém hơn một chút. Tuy nhiên, trong tình huống này, do giới hạn về những ký tự thực tế có thể xảy ra trong tên người dùng , cả hai đều ổn.

Giải thích, lợi ích và nhược điểm

Tôi sử dụng getentchủ yếu vì nó chấp nhận tên người dùng làm đối số để hạn chế đầu ra của nó, nhưng cũng vì nó phổ biến hơn một chút so với kiểm tra /etc/passwdtrực tiếp, trong trường hợp phương tiện xác thực và cơ sở dữ liệu mật khẩu được cung cấp bởi các dịch vụ mạng.

Phương pháp này có lợi ích bổ sung hơn ls /homelà, trên các hệ thống có /homephân vùng riêng , lost+foundthường xuất hiện trong đầu ra của ls /home.

  • Với phương thức mạnh hơn được trình bày ở trên, lost+foundsẽ chỉ xuất hiện nếu có người dùng (người hoặc không) được gọi lost+found, điều này là không thể.
  • Nhưng nếu bạn đang nhập lệnh tương tác thay vì viết một tập lệnh, ls /homethì tốt thôi-- bạn biết bạn không có người dùng được gọi lost+found.

Không thường xuyên, phương pháp này (trong bất kỳ biến thể nào ở trên) sẽ tạo ra đầu ra không đạt yêu cầu:

  • Nếu thư mục nhà của người dùng tồn tại bên ngoài /homehoặc hoàn toàn không có, điều này cho thấy nhưng không ngụ ý tài khoản không nên được coi là đại diện cho người dùng. Phương pháp này chỉ liệt kê người dùng khi có một thư mục cùng tên /home.
  • Nếu bạn đã tạo các thư mục bổ sung trong /homeđó thực sự không phải là thư mục chính của bất kỳ ai chúng có cùng tên với một người dùng không phải là người hiện tại - hoặc bao gồm các từ được phân tách bằng khoảng trắng, một hoặc nhiều từ có cùng tên với tư cách là một người dùng không phải con người hiện tại - sau đó một số người dùng không phải là con người có thể được đưa vào đầu ra.
    (Phương pháp này có thể được thực hiện với một vòng lặp và các lệnh riêng biệt getent, vì vậy việc tách từ không tạo ra đầu ra giả. Nhưng sự phức tạp không được bảo đảm; về cơ bản, nếu bạn sử dụng /homenhư một nơi khác ngoài thư mục gốc của người dùng, phương thức này sẽ không tạo ra đầu ra đáng tin cậy.)

Tạo đơn giản kiểm tra UID

Nếu bạn quyết định thực hiện một phương pháp kiểm tra ID người dùng để đảm bảo chúng nằm trong phạm vi có khả năng cho các tài khoản đại diện cho con người, như trong câu trả lời được chấp nhận hoặc câu trả lời của Oli's , thì tôi khuyên bạn nên làm điều này cho ngắn gọn:

getent passwd | grep -oP '^[^:]+(?=:x:\d{4}:)'

Điều này sử dụng biểu thức chính quy Perl ( -P) để hiển thị:

  • văn bản ở đầu một dòng ( ^) không chứa :s ( [^:]+) - đây là trường đầu tiên, cũng như :dấu phân cách trường trongpasswd
  • có trước nhưng không bao gồm ( (?= )) trường mật khẩu x- phải luôn như vậy x, vì trong băm mật khẩu Ubuntu được lưu trữ trong shadowcơ sở dữ liệu, không phải passwdcơ sở dữ liệu dễ đọc trên thế giới
  • và một trường UID bao gồm chính xác 4 chữ số ( :\d{4}:).

Do đó, đây là một biến thể ngắn hơn đáng kể và có phần đơn giản hơn của kỹ thuật trong câu trả lời được chấp nhận . (Kỹ thuật được mô tả ở đó cũng hoạt động tốt và nó có lợi ích là có thể di chuyển đến các hệ thống grepkhông phải GNU / Linux mà không hỗ trợ -P.)

Xem xét lại phạm vi UID "con người"

Nếu bạn muốn chứa UID rất cao và kiểm tra nobodyrõ ràng, bạn có thể sử dụng phương pháp trong câu trả lời của Oli's . Tuy nhiên, bạn có thể cân nhắc, nếu người dùng có UID rất cao nên thực sự là người, hoặc nếu họ có nhiều khả năng là một người dùng không phải là người đặc biệt khác (như nobody). Trong thực tế những người dùng như vậy - bên cạnh nobody- không phổ biến, vì vậy thực sự đây là một lời kêu gọi phán xét từ phía bạn.

Một sự thỏa hiệp có thể là liệt kê người dùng trong phạm vi UID thực sự được gán cho người dùng mới được tạo, không thuộc "hệ thống". Bạn có thể kiểm tra điều này trongadduser.conf :

$ grep -E '^(FIRST|LAST)_UID' /etc/adduser.conf
FIRST_UID=1000
LAST_UID=29999

Dưới đây là hai cách để liệt kê người dùng có UID nằm trong khoảng từ 1000 đến 29999:

getent passwd | grep -oP '^[^:]+(?=:x:[12]?\d{4}:)'
getent passwd | awk -F: '999<$3 && $3<30000 {print $1}'

Nếu bạn muốn được làm hài lòng phong cách, basenamelà xấu xí. Nó không tốt hơn ls. Lý do chính mà chúng tôi không phân tích ls là vì đó là một công việc có thể được thực hiện bằng các công cụ khác an toàn và sạch sẽ hơn nhiều, không phải là phong cách. Trong trường hợp này, vỏ : cd /home; getent passwd *.
muru

Tôi đồng ý với bạn trên / nhà là không đáng tin cậy (nó vô dụng đối với tôi, xem câu trả lời của tôi). Tôi chỉ nói rằng nếu bạn định giảng về phong cách, hãy chờ đợi nitpicking.
muru

@muru Tôi thấy cách phrasing ban đầu của tôi có thể đánh lừa mọi người nghĩ rằng tránh phân tích cú pháp lsthường là về phong cách. Điểm đạn thứ 2 về "đầu ra không đạt yêu cầu" đã đề cập đến vấn đề này, nhưng nó sẽ xuất hiện trong phần sau. Tôi đã điều chỉnh lại để làm rõ lý do tại sao phân tích cú pháp lslà phù hợp trong tình huống này . Mặc dù cd /home; getent passwd *có một hình thức thường biểu thị cho cách tiếp cận âm thanh hơn, tôi đã tránh nó để không khiến độc giả tin vào nội dung của các /homethư mục, với các mục được thêm kỳ lạ không tương ứng với người dùng thực, vẫn có thể dựa vào một cách nào đó để làm hướng dẫn cho những gì người dùng tồn tại.
Eliah Kagan

1

TL; DR : chỉ người dùng con người có SystemAccount = false

Một cách khác là liệt kê đầu ra trong khi bỏ qua root ls /var/lib/AccountsService/users/ | grep -v root. Bây giờ, có một cách giải quyết - gdm, màn hình chào / đăng nhập (hoặc chính thức hơn là trình quản lý máy tính để bàn) cũng được liệt kê dưới dạng người dùng. Vì vậy, chỉ từ danh sách, chúng tôi không thể biết nếu gdm là con người hay không.

Một cách tiếp cận hiệu quả và đúng đắn hơn là duyệt qua các tệp trong thư mục đó và tìm ra người dùng nào được liệt kê là có SystemAccount=false. Dưới một lớp lót đạt được rằng

grep SystemAccount=false /var/lib/AccountsService/users/* | awk -F '/' '{gsub(":","/");print $6}'


1
Mặc dù đôi khi tiện dụng, điều này thất bại trong một số tình huống tương đối phổ biến. Ví dụ: trên hệ thống tối thiểu Ubuntu 15.04 của tôi (được cài đặt từ mini.isovà không có trình quản lý hiển thị hoặc X11 được cài đặt), tôi có một tài khoản người dùng - nhưng vẫn /var/lib/AccountsService/userslà một thư mục trống. Tôi hy vọng điều này sẽ tương tự không hoạt động trên bản cài đặt Ubuntu Server ngoài luồng. Hơn nữa, khi điều này không hoạt động, nó thực hiện theo một khái niệm hơi hạn chế về điều khiến tài khoản người dùng trở thành "con người": làm cho người dùng có useradd, ngay cả khi không --system , không tạo tệp AccountsService/users.
Eliah Kagan

1

Tham gia bữa tiệc, tôi giám sát một hệ thống mạng bằng LDAP, có các thư mục chính bên ngoài /homevà UID (do trục trặc kịch bản) trong hàng triệu. Không có câu trả lời hiện tại, do đó, làm việc. Thử nghiệm phù hợp với tôi là kiểm tra xem người dùng có vỏ đăng nhập hợp lệ hay không. Một vỏ hợp lệ là một vỏ được liệt kê trong /etc/shells. Hình thức đơn giản nhất:

getent passwd | grep -wFf /etc/shells

Tệp có thể chứa các nhận xét (hoặc dòng trống), vì vậy người ta có thể phải lọc chúng ra:

getent passwd | grep -wFf <(grep '^/' /etc/shells)

+1 Đây có thể là cách tiếp cận mạnh mẽ nhất được đề xuất cho đến nay. Mặc dù nó có nhược điểm là hiển thị root( có lẽ không nên được coi là người dùng, vì con người thường tạm thời root và vì mục đích cụ thể, thay vì sử dụng nó cho công việc thường xuyên của họ), có vẻ như đó là khả năng thất bại ít nhất bất kỳ cách chính. Các phương pháp trong câu trả lời khác (kể cả tôi) có thể thất bại, tùy thuộc vào phương pháp, nếu thư mục nhà đang không ở trong /home, rác khác trong /home, UID là lạ, hoặc hệ thống không sử dụng một DM. Câu trả lời này hoạt động khá tốt trong tất cả các kịch bản.
Eliah Kagan

1

Trên các hệ thống buntu, người dùng thông thường (nghĩa là người dùng) có UID bắt đầu bằng 1000 được gán liên tục cho họ khi tài khoản của họ được tạo lần đầu tiên. Tất cả những điều này có nghĩa là tài khoản đầu tiên được tạo trên hệ thống buntu có UID là 1000. Tài khoản tiếp theo được tạo có UID là 1001. Cứ tiếp tục như vậy.

Vì vậy, cách đơn giản nhất để liệt kê tất cả các tài khoản người dùng có trên hệ thống, theo tôi, là kiểm tra xem cột thứ ba trong /etc/passwdtệp chứa UID của người dùng có lớn hơn hoặc bằng 1000 và nhỏ hơn không, giả sử, 2000 (rất khó để một máy tính để bàn thông thường có nhiều hơn một nghìn tài khoản người dùng, bạn có nghĩ vậy không?):

$ awk -F$':' '{ if ($3 >= 1000 && $3 < 2000) print $1; }' /etc/passwd

Cảm ơn đã giải thích câu trả lời của Oli's với các chi tiết. Bạn cũng cần lọc ra nobody. =)
anatoly techtonik

1
Bạn không phải làm thế bởi vì không ai có UID là 65534 và do đó, nó sẽ tự động được lọc ra như tất cả các tài khoản người dùng khác.
misha
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.