列出所有人类用户


19

如何列出我创建的所有人类用户?我已经尝试过了cat /etc/passwd,它只列出了很多东西。

Answers:


18

人类用户的UID从1000开始,因此您可以使用该事实过滤掉非人类用户:

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

这会从中切出第一个(用户名)和第三个(UID)以冒号分隔的字段/etc/passwd,然后过滤以冒号和四位数结尾的结果行,然后从中切出第一个(用户名)字段,为您提供一个列表UID在1000到9999之间的用户。

如果您的系统上有超过九千个用户,这将失败-但是有必要将结果限制为4位UID,以免被捕获nobody(UID 65534)。


15

这几乎完成了可接受的答案,只是一个命令而不是三个命令:

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

还要感谢Karel的评论,nobody用户也被过滤掉了。


@karel是的,也许。我没有按UID进行过滤,而是明确地过滤出该用户名。可能有一个合法用户的UID很高的原因...谁知道;)
Oli

9

我个人喜欢只使用:

ls /home

不可否认,这不是用户列表,而是其主目录列表。当前系统上现有的人工用户将在中拥有主目录/home,但是您可能还会看到被删除的过去用户的主目录。

这对我有用,也可能对您有用。例如,如果您要删除原来不存在的用户帐户(nonexistent-user),然后运行命令

sudo deluser nonexistent-user

它只会告诉您该用户不存在。


+1这种方法很简单,这是大多数有经验的用户实际上会做的,而且我认为它的有效性不亚于检查一系列UID的方法。与用户的UID低于1000(毕竟,这是阻止显示管理器列出的最常见的方法)相比,用户在外部/home(未链接到/home)的主目录似乎不太可能用户登录屏幕上,有时可以由人类用户完成)。一个相对较小的缺点是,lost+found它将在具有单独/home分区的系统上列出。
伊莱亚·卡根

不过,这是一个小问题:如果使用创建用户会发生什么useradd --no-create-home username
Sergiy Kolodyazhnyy,2015年

@Serg我认为这可以归结为问题描述中固有的模糊性。没有主目录的帐户是否真的代表人类用户?实际上,此类帐户通常(尽管不总是如此)用于高度专业化的任务(通常由拥有自己独立帐户的人使用)或仅通过特定的受限服务访问系统的用户使用。当然,还有另一个用例useradd --no-create-home-主目录可能已经存在或可能在此后不久创建-但该ls /home方法在这些情况下效果很好。
伊莱亚·卡根

4

尽管这似乎是一个明确的主意,但实际上,人类使用者的含义存在歧义。用户帐户是否仅由于专门用于人类用户的目的而被故意隐藏在登录屏幕上?ubuntu实时CD上的用户(UID 999)如何?而且,Ubuntu中的来宾帐户是即时创建的,并在注销后销毁;他们是人类使用者吗?可以设计更多示例。

因此,给出多个非等效的答案是合适的。Saige Hamblin的运行解决方案ls /home是人们的实际操作,除非您正在编写脚本,否则可能应该使用它。

制作ls /home更稳健

但是,也许您的用户已被删除,但其主目录仍存在于中/home,并且您必须避免列出它们。或者,也许由于某些其他原因,您必须确保仅/home列出与真实帐户相对应的条目。

在这种情况下,我建议通过这些名字都是在/homegetent(检索passwd与这些名字用户的条目),然后分离并显示只是用户名字段(与grepsedawk,按您的喜好)。这些中的任何一个都可以:

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

这应该很好用,因为您的用户帐户中不应包含空格或控制字符。不能,除非重新配置Ubuntu以允许它;如果这样做,您会遇到更大的问题。因此,解析ls中常见的问题不适用。但是,即使在这里真的可以,但是如果您考虑用ls美观或令人讨厌的习惯替换命令,您可能更喜欢:

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

这些也不包含空格或控制字符。我之所以提供它们,仅是因为$(ls /home)即使正确也看起来还是错误的,从而以错误的方式擦拭了许多用户。在大多数情况下,确实有充分的理由要避免进行解析ls,并且在这些情况下,解析的basename -a坏处通常很少。但是,在这种情况下,由于实际上在用户名中可能出现什么字符的限制,它们都很好。

解释,好处和缺点

getent之所以使用它,主要是因为它接受用户名作为参数来限制其输出,还因为它比/etc/passwd直接检查更通用,以防身份验证设施和密码数据库由网络服务提供。

这种方法的另一个好处ls /home是,在具有单独/home分区的系统上,lost+found通常出现在的输出中ls /home

  • 使用上面介绍的更健壮的方法,lost+found只有在碰巧有一个用户(无论是人类还是不是)被称为时才会出现lost+found
  • 但是,如果您以交互方式输入命令而不是编写脚本,那ls /home很好- 知道您没有人类用户lost+found

这种方法(在上述任何一种变化中)很少会产生不令人满意的输出:

  • 如果用户的主目录位于外部/home,或根本不存在,则表明但并不意味着该帐户不应该代表人类用户。仅当中存在相同名称的目录时,此方法才会列出用户/home
  • 如果您在其中创建的其他目录/home实际上不是任何人的主目录,并且它们碰巧与现有的非人类用户相同的名称-或由空格分隔的单词组成,其中一个或多个具有相同的名称作为现有的非人类用户-那么某些非人类用户可能会包含在输出中。
    (此方法可以通过循环和单独的getent调用来实现,因此,单词拆分不会产生虚假输出。但是并不能保证复杂性;从根本上讲,如果您/home将其用作用户主目录的存放位置,则此方法将无法产生可靠的输出。)

简化UID检查

如果您决定采用一种检查用户ID的方法,以确保它们在代表人类的帐户的可能范围内(例如公认的答案Oli的答案),那么为简洁起见,我建议这样做:

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

这使用Perl正则表达式-P)显示:

  • ^不包含:s([^:]+)的行()开头的文本-这是第一个字段,:其中的字段分隔符passwd
  • 之前但不包含((?= ))密码字段x-应该始终为x,因为在Ubuntu中,密码哈希存储在shadow数据库中,而不是世界可读的passwd数据库中
  • 和一个UID字段,该字段完全由4位数字(:\d{4}:)组成。

因此,这是公认答案中该技术的明显更短,更简单的变体。(那里描述的技术也很好用,它的好处是可以移植到grep不支持的非GNU / Linux系统上-P。)

重新考虑“人类” UID范围

如果要容纳非常高的UID并进行nobody明确检查,则可以使用Oli的answer中的方法。但是,您可能要考虑,如果UID很高的用户确实应该被认为是人类用户,或者他们更有可能是其他一些特殊用途的非人类用户(例如nobody)。在实践中,此类用户(除其他外)nobody并不常见,因此,这实际上是您的判断要求。

可能的折衷办法是列出实际分配给新创建的非“系统”用户的UID范围内的用户。您可以adduser.conf以下位置进行检查:

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

以下是列出UID范围从1000到29999的用户的两种方法:

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

如果您想在造型上令人愉悦,那就basename很难看。没有比这更好的了ls。我们不解析ls的原则原因是,这项工作可以通过其他工具更安全,更干净地完成,而不是使用样式。在这种情况下,外壳:cd /home; getent passwd *
muru

我同意您对/ home的不信任(对我来说这毫无用处,请参阅我的回答)。我只是说,如果您要传讲风格,请期待挑剔。
muru,2015年

@muru我明白我原来的措辞可能会误导人们以为避免解析ls通常是关于样式的。关于“输出不令人满意”的第二点要点涵盖了该问题,但它会在后面的部分中出现。我已经改写清楚了,为什么在这种情况下解析ls才是合适的。尽管采用某种形式通常表示一种更合理的方法,但我避免使用这种形式是为了避免使读者相信目录的内容以及添加了与实际用户不对应的怪异条目,仍然可以以某种方式作为指导内容用户存在。cd /home; getent passwd */home
伊利亚·卡根

1

TL; DR:仅人类用户具有SystemAccount = false

另一种方法是在忽略root的情况下列出的输出 ls /var/lib/AccountsService/users/ | grep -v root。现在,有一个怪癖-gdm,一个迎宾/登录屏幕(或更正式的说是桌面管理器)也被列为用户。因此,仅从列表中我们就无法确定gdm是否是人类。

一种更有效,更正确的方法是浏览该文件夹中的文件,并找出列出哪些用户SystemAccount=false。一线波纹管实现了

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


1
尽管有时很方便,但是在某些相对常见的情况下却无法实现。例如,在我的Ubuntu 15.04最小系统上(从中安装mini.iso并且没有安装显示管理器或X11),我有一个人工用户帐户-仍然/var/lib/AccountsService/users是一个空目录。我希望这在开箱即用的Ubuntu Server安装上同样不起作用。此外,当此方法起作用时,它在某种程度上限制了使用户帐户“人性化”的条件:拥有useradd甚至没有 的用户--system都不会在中创建文件AccountsService/users
伊莱亚·卡根

1

加入聚会后,我监督了使用LDAP的网络系统,外部有主目录,/home而UID(由于脚本故障)有数百万。因此,当前的答案均无效。对我有用的测试是检查用户是否具有有效的登录外壳。有效的外壳是中列出的外壳/etc/shells。最简单的形式:

getent passwd | grep -wFf /etc/shells

该文件可能包含注释(或空行),因此可能必须将其过滤掉:

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

+1这可能是迄今为止建议的最可靠的方法。虽然它显示的缺点root(这也许不应该被认为是人类用户,因为人类通常根暂时的,为特定目的,而不是用它为自己的日常工作),现在看来似乎是最有可能失败的任何主要方式。在其他的答案(包括我)的方法可能会失败,取决于方法,如果主目录不在/home,其他垃圾/home,的UID是怪异的,或者系统不使用DM。在所有这些情况下,此答案都非常有效。
伊利亚·卡根

1

在Buntu系统上,普通用户(即人工用户)具有以1000开头的UID,这些UID在首次创建其帐户时会顺序分配给他们。所有这些归结为,在Buntu系统上创建的第一个帐户的UID为1000。下一个创建的帐户的UID为1001。依此类推。

因此,在我看来,列出系统上存在的所有人类用户帐户的最简单方法是检查/etc/passwd文件中包含用户UID 的第三列是否大于或等于1000且小于等于2000 (对于典型的台式机来说,拥有一千个以上的用户帐户是非常不可能的,您是不是这样认为?):

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

感谢您详细解释Oli的答案。您还需要过滤掉nobody。=)
anatoly techtonik

1
您不必这样做,因为没有人的UID为65534,因此会像其他所有非人类用户帐户一样被自动过滤掉。
misha
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.