如何编写一个 shell 脚本来删除 Linux 系统上所有 UID > 1000 的本地用户帐户?
这是我到目前为止所拥有的:
#!/bin/bash
for userid in `/etc/passwd`
do
if ((“userid” >= 1000)); then
userdel -r $user
done
如何设置删除所有 UID > 1000 的账户的条件?这是我没能找到的部分。我什至不确定到目前为止我所做的是否正确,但我在其他一些帖子上读到了它,该帖子有类似的问题,但略有不同。
答案1
以下awk
命令将输出 UID 大于或等于 1000 的所有本地用户的用户名,并会跳过名称为 的任何用户nobody
(这是您最有可能的用户)不想要删除):
awk -F : '$3 >= 1000 && $1 != "nobody" { print $1 }' /etc/passwd
它将/etc/passwd
文件解析为一组带有 -:
分隔字段的基于行的记录。它测试第三个字段的值是否大于或等于 1000,确保第一个字段不是nobody
,然后打印第一个字段。您可能希望将第二个测试更改为$1 != "nobody"
避免$3 < 10000
访问任何具有高 UID 的特殊帐户。
然后,您可以使用循环来读取名称并一次删除它们(请参阅史蒂芬的回答了解如何使用xargs
来执行此操作):
awk -F : '$3 >= 1000 && $1 != "nobody" { print $1 }' /etc/passwd |
while IFS= read -r name; do
userdel -r "$name"
done
答案2
应该是这样的:
getent passwd |
awk -F: '$3 >= 1000 {print $1}' |
xargs -n1 -rd '\n' echo userdel -r --
echo
(如果看起来正确,则删除)。这假定了 的 GNU 实现xargs
,但这通常用于非嵌入式 Linux 系统(您将在其上进行用户管理的系统)。
getent passwd
转储 passwd 用户数据库,无论它是否存储在/etc/passwd
、postgresql、sqlite3、LDAP...
在该数据库转储中,条目以冒号分隔,第一个字段是用户名,第三个字段是用户 ID。
awk
是处理此类数据的明显选择。
我们使用-F:
( 的缩写-v FS=:
)调用它,将字段分隔符设置为:
,并且对于每条记录,如果第三个字段是大于或等于 1000 的数字,我们将打印第一个字段。
xargs
获取该输出(被视为n
ewlined
限制),并且对于每个1
条目,使用echo
、和该条目作为参数调用 、 userdel
、 。-r
--
如果您只想考虑 中的用户名,请替换getent passwd |
为。</etc/passwd
/etc/passwd
正如@Kusalananda 所说,可能有一些系统帐户,例如nobody
您不想删除的帐户。
例如,在我的系统上,我发现:
libvirt-qemu:x:64055:108:Libvirt Qemu,,,:/var/lib/libvirt:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
因此,您可能想在您的选择中添加更多条件,例如$3 >= 1000 && $3 < 60000
或$3 >= 1000 && $6 ~ "^/home/"
(下的主目录/home
)或$7 !~ "nologin"
(shell 不包含 nologin),或某个组的成员身份,或具有有效的密码...
请注意,userdel
标准输入将是 /dev/null,因此它将无法提示您任何内容。为了避免这种情况,您可以将其改写为:
xargs -n1 -rd '\n' -a <(
getent passwd |
awk -F: '$3 >= 1000 {print $1}'
) echo userdel -r --
这次xargs
从后面传递的文件-a
而不是 stdin 中获取输入,并userdel
单独保留 stdin 。
在这种情况下,文件名是 ksh 风格的进程替换(bash 也支持)的结果,其中<(...)
扩展为管道的路径,末尾由getent | awk
.