lak*_*rda 18 bash shell-script eval
我想列出机器上的所有用户目录。通常,我会这样做:
ls -l /home
Run Code Online (Sandbox Code Playgroud)
但是我在一个脚本中使用它,该脚本将部署在其他机器上,也许在他们不称之为家的机器上(例如 myHome)。所以我想把它概括为ls -l ~
. 但它只列出我的用户主目录而不是所有用户主目录名称(基本上我想获得机器上用户名的列表)。我怎样才能概括它?
Sté*_*las 49
许多系统有一个getent
对list命令或查询的内容名称服务数据库一样passwd
,group
,services
,protocols
...
getent passwd | cut -d: -f6
Run Code Online (Sandbox Code Playgroud)
将列出可以枚举的数据库中所有用户的主目录(第 6个冒号分隔字段)。
用户名本身在第一个字段中,因此对于用户名列表:
getent passwd | cut -d: -f1
Run Code Online (Sandbox Code Playgroud)
(请注意,这并不意味着这些用户可以登录系统或他们的主目录已经创建,而是系统知道他们,他们可以转换为用户 ID)。
对于无法枚举的数据库,您可以尝试单独查询每个可能的用户 ID:
getent passwd {0..65535} | cut -d: -f1,6
Run Code Online (Sandbox Code Playgroud)
(这里假设 uids 停止在 65535(一些系统支持更多)和一个支持 zsh{x..y}
形式的大括号扩展的 shell )。但是您不希望在用户数据库联网(并且本地缓存有限)的系统上经常这样做,例如 LDAP、NIS+、SQL...,因为这可能意味着大量的网络流量(并加载到目录服务器上) ) 进行所有这些查询。
这也意味着,如果有多个用户共享相同的 uid,则每个 uid 只能获得一个条目,因此会错过其他用户。
如果你没有getent
,你可以求助于perl
:
perl -le 'while (@e = getpwent) {print $e[7]}'
Run Code Online (Sandbox Code Playgroud)
对于getent passwd
($e[0]
对于用户名),或:
perl -le 'for ($i=0;$i<65536;++$i) {
if (@e = getpwuid $i) {print $e[0] ": " $e[7]}}'
Run Code Online (Sandbox Code Playgroud)
因为getent passwd {0..65535}
有相同的警告。
在 shell 中,您可以使用~user
来获取 的主目录user
,但在大多数 shell 中,这仅适用于有限的用户名集(该~
扩展运算符支持的用户名中允许的字符列表因 shell 不同而不同)并且使用几个外壳(包括bash
),~$user
将无法工作(eval
当用户名存储在变量中时,您需要求助于)。而且您仍然需要找到一种方法来获取用户名列表。
一些 shell 内置支持获取用户名列表。
bash
:compgen -u
将返回可以枚举的数据库中的用户列表。zsh
:$userdirs
关联数组将用户名映射到其主目录(也仅限于可以枚举的数据库,但如果您对~user
不可枚举数据库中的用户进行扩展,则会向 中添加一个条目$userdirs
)。所以你可以这样做:
printf '%s => %s\n' "${(kv@)userdirs}"
Run Code Online (Sandbox Code Playgroud)
列出用户及其主目录。
tcsh
,fish
以及yash
其他三个可以完成用户名的外壳程序(例如,在完成~<Tab>
参数时),但它们看起来并不能让您以编程方式获取该用户名列表。
Eig*_*ony 17
列出用户主目录的更好方法是/etc/passwd
从那里解析和提取它们,而不是对它们可能在哪里做出任何假设。
从你的第二条评论来看,你实际上想要的是用户名,而不是他们的主目录,在这种情况下,/etc/passwd
无论如何都是更好的选择。请注意,某些 Linux / UNIX 机器将配置其他用户身份验证机制(例如 LDAP),因此最终,您的查询比您最初想象的要复杂,但这/etc/passwd
是一个很好的起点。
小智 8
简短的回答:
compgen -u
Run Code Online (Sandbox Code Playgroud)
中等答案:由于您正在使用bash
,您可以列出所有可能的~
使用完成compgen -A user
。这是一个很常见的用法,可以缩写为compgen -u
。作为内置的 shell,compgen
没有自己的手册页。相反,请参阅bash(1)以获取文档并阅读有关Programmable Completion的部分。
更彻底的替代方案
如果您非常关心可移植性,您甚至可能无法依赖其他具有bash
. 在这种情况下,请执行以下操作:
(getent passwd ||
dscl . -ls /Users dsAttrTypeNative:homeDirectory ||
nidump passwd ||
cat /etc/passwd) 2>/dev/null | cut -d: -f6
Run Code Online (Sandbox Code Playgroud)
解释
长答案会尝试一切,所以它几乎可以在任何 UNIX 系统上工作,无论它是否使用较新的 /etc/nsswitch.conf(GNU/Linux 和 BSD 都附带getent
)、传统的 UNIX passwd 平面文件、MacOS 的目录服务¹ ( dscl
),甚至是较旧的、以猫为主题的 MacOS X 版本和 NeXTSTEP ( nidump
)。
简单
但是,您需要多大的便携性?Unix 有很多做事的方式,有时更简单的就足够了。如果您必须选择一个,我建议您getent passwd | cut -d: -f6
使用 shell 脚本。²
脚注 ¹:我有一段时间没有使用过 MacOS,所以如果有人可以为我确认我的语法正确(并且输出不包含任何会弄乱的杂散冒号cut
),那就太好了。谢谢。
脚注²:我推荐的和我做的可能不同。就个人而言,我会更频繁地cut -d: -f1 /etc/passwd
在命令行中使用传统的。经过几十年的重复,我的手指可以打字,而我的大脑正在处理其他事情。
归档时间: |
|
查看次数: |
38310 次 |
最近记录: |