![如何列出所有用户名和/或主目录?](https://linux22.com/image/123196/%E5%A6%82%E4%BD%95%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%2F%E6%88%96%E4%B8%BB%E7%9B%AE%E5%BD%95%EF%BC%9F.png)
我想列出机器上所有用户的目录。通常,我会这样做:
ls -l /home
但我在一个脚本中使用它,该脚本将部署在其他人的机器上,也许在那些他们不称之为家的机器上(例如 myHome)。
所以我想将其概括为ls -l ~
.但它只是列出我的用户的主目录,而不是所有用户的主目录(基本上我想获取计算机上的用户名列表)。
我该如何概括它?
答案1
许多系统都有一个getent
命令来列出或查询文件的内容名称服务数据库如passwd
, group
, services
, protocols
...
getent passwd | cut -d: -f6
将列出数据库中所有用户的主目录(第 6 个冒号分隔字段)列举的。
用户名本身位于第一个字段中,因此对于用户名列表:
getent passwd | cut -d: -f1
(注意,这并不意味着这些用户可以登录系统或者他们的主目录已经创建,而是说他们是系统已知的,他们可以被转换为用户ID)。
对于无法枚举的数据库,您可以尝试单独查询每个可能的用户ID:
getent passwd {0..65535} | cut -d: -f1,6
(这里假设 uids 停止于 65535(某些系统支持更多)并且 shell 支持 zsh 的{x..y}
大括号扩展形式)。但是您不想在用户数据库联网(并且本地缓存有限)的系统(例如 LDAP、NIS+、SQL)上经常这样做,因为这可能意味着大量网络流量(并在目录服务器上加载) )来进行所有这些查询。
这也意味着,如果有多个用户共享相同的 uid,则每个 uid 只能获得一个条目,因此请忽略其他条目。
如果你没有getent
,你可以求助于perl
:
perl -le 'while (@e = getpwent) {print $e[7]}'
for getent passwd
($e[0]
对于用户名),或者:
perl -le 'for ($i=0;$i<65536;++$i) {
if (@e = getpwuid $i) {print $e[0] ": " $e[7]}}'
具有getent passwd {0..65535}
相同的警告。
在 shell 中,您可以使用~user
获取 的主目录user
,但在大多数 shell 中,这只适用于有限的用户名集(该~
扩展运算符支持的用户名中允许的字符列表因 shell 而异)并且一些 shell(包括bash
)将无法工作(当用户名存储在变量中时,~$user
您需要求助)。eval
而且您仍然需要找到一种方法来获取用户名列表。
有些 shell 具有内置支持来获取用户名列表。
bash
:compgen -u
将返回数据库中可枚举的用户列表。zsh
:$userdirs
关联数组将用户名映射到其主目录(也仅限于可枚举的数据库,但如果您~user
对不可枚举数据库中的用户进行扩展,则会向 中添加一个条目$userdirs
)。所以你可以这样做:printf '%s => %s\n' "${(kv@)userdirs}"
列出用户及其主目录。
tcsh
、fish
和yash
是其他三个可以完成用户名的 shell(例如完成~<Tab>
参数时),但它们看起来并不能让您以编程方式获取用户名列表。
答案2
列出用户主目录的更好方法是/etc/passwd
从那里解析和提取它们,而不是对它们可能在哪里做出任何假设。
从您的第二条评论来看,您实际上需要用户名,而不是他们的主目录,在这种情况下,/etc/passwd
无论如何都是更好的选择。请注意,某些 Linux/UNIX 计算机将配置其他用户身份验证机制(例如 LDAP),因此最终您的查询比您最初想象的要复杂,但这/etc/passwd
是一个很好的起点。
答案3
简短的回答:
compgen -u
中等答案:既然您正在使用bash
,您可以列出所有可能的~
使用补全compgen -A user
。这是很常见的用法,可以缩写compgen -u
。作为 shell 内置程序,compgen
没有自己的手册页。相反,请参阅重击(1)获取文档并阅读有关部分可编程完成。
更彻底的替代方案
如果您非常关心可移植性,您甚至可能无法依赖其他具有bash
.在这种情况下,请执行以下操作:
(getent passwd ||
dscl . -ls /Users dsAttrTypeNative:homeDirectory ||
nidump passwd ||
cat /etc/passwd) 2>/dev/null | cut -d: -f6
解释
长答案尝试了一切,所以它几乎可以在任何 UNIX 系统上工作,无论它是否使用较新的 /etc/nsswitch.conf (GNU/Linux 和 BSD 都带有getent
)、传统的 UNIX passwd 平面文件、MacOS 的 Directory服务 1 ( dscl
),甚至是较旧的、以猫为主题的 MacOS X 版本和 NeXTSTEP ( nidump
)。
简单
但是,您需要多便携? Unix 有很多做事的方式,有时更简单就足够了。如果您必须选择其中之一,我建议getent passwd | cut -d: -f6
您使用 shell 脚本。²
脚注 1:我已经没有使用过 MacOS 了,所以如果有人可以帮我确认我的语法是正确的(并且输出不包含任何会造成混乱的冒号cut
),那就太好了。谢谢。
脚注 ²:我的建议和我所做的可能会有所不同。就我个人而言,我会更频繁地cut -d: -f1 /etc/passwd
在命令行中使用传统的方式。经过几十年的重复,我的手指可以打字,而我的大脑却在做其他事情。
答案4
关于什么ls -l ~/..
?这列出了主目录父目录中的所有目录。