列出所有人类用户

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

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

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

这会从/etc/passwd第一个(用户名)和第三个(UID)冒号分隔的字段,然后过滤以冒号和四位数结尾的结果行,然后从中删除第一个(用户名)字段,离开使用UID介于1000和9999之间的用户列表。

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

这几乎就是接受的答案 ,只用一个命令而不是三个命令:

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

感谢Karel在评论中, nobody用户也被过滤掉了。

我个人喜欢只使用:

 ls /home 

不可否认,这不是用户列表,而是他们的主目录列表。 目前系统上现有的人类用户将在/home拥有主目录,但您也可以看到已删除的过去用户的主目录。

这适用于我的目的,也可能适用于您的目的。 例如,如果您要删除不再存在的用户帐户( nonexistent-user )并运行命令

 sudo deluser nonexistent-user 

它会告诉你这个用户不存在。

虽然它看起来像一个明确的想法,但实际上人类用户的意义含糊不清。 用户帐户是否故意隐藏在登录屏幕上,因为它仅用于特定目的(但是由人类)用户? Live CD上的ubuntu用户(UID 999)怎么样? Ubuntu中的访客帐户是在运行时创建的,并在注销后销毁; 他们是人类用户吗? 可以设计更多的例子。

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

ls /home更健壮

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

在这种情况下,我建议将/home的所有内容的名称传递给getent (以检索具有这些名称的用户的passwd条目),然后隔离并显示用户名字段(使用grepsedawk ,根据您的偏好) )。 其中任何一个都可以:

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

这应该很好,因为你的名字中不应该有用空格或控制字符的用户帐户; 不能重新配置Ubuntu来允许它 ; 如果你这样做,你会遇到更大的问题。 因此,解析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更通用,以防身份validation设施和密码数据库由网络服务提供。

这种方法比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 )来显示:

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

因此,在接受的答案中,这是该技术的明显更短且更简单的变体。 (这里描述的技术也可以正常工作,并且它具有可移植到非GNU / Linux系统的好处,其grep不支持-P 。)

重新考虑“人类”UID范围

如果您想要容纳非常高的UID并明确检查nobody ,您可以在Oli的答案中使用该方法。 但是,您可能希望考虑具有非常高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}' 

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

另一种方法是列出输出,同时忽略root ls /var/lib/AccountsService/users/ | grep -v 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}'

加入聚会,我使用LDAP监督网络系统,在/home和UID(由于脚本故障)之外有数百万的主目录。 因此,目前的答案都不起作用。 对我有用的测试是检查用户是否具有有效的登录shell。 有效的shell是/etc/shells列出的/etc/shells 。 最简单的forms:

 getent passwd | grep -wFf /etc/shells 

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

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

在buntu系统上,常规用户(人类用户)具有以1000开头的UID,这些UID在首次创建帐户时按顺序分配给他们。 所有这一切归结为在buntu系统上创建的第一个帐户的UID为1000.创建的下一个帐户的UID为1001.依此类推。

因此,在我看来,列出系统中存在的所有人类用户帐户的最简单方法是检查/etc/passwd文件中包含用户UID的第三列是否大于或等于1000且小于,比方说,2000年(对于典型的台式PC而言,拥有超过一千个用户帐户的可能性不大,你不这么认为吗?):

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