我正在尝试使用 批量设置一些用户帐户密码chpasswd
。密码应该随机生成并打印到stdout
(我需要将它们写下来或将它们放入密码存储中),并且也传递到chpasswd
.
天真地,我会这样做
{
echo student1:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
echo student2:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
} | tee >(chpasswd)
但是,我担心将新密码作为命令行参数传递给echo
,因为参数通常对 中的其他用户可见ps -aux
(尽管我从未echo
在 中看到任何行出现ps
)。
是否有其他方法可以在返回的密码前添加一个值,然后将其传递到chpasswd
?
答案1
您的代码应该是安全的,echo
因为它是内置的 shell,因此不会显示在进程表中。
这是一个替代解决方案:
#!/bin/bash
n=20
paste -d : <( seq -f 'student%.0f' 1 "$n" ) \
<( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd
这将创建您的学生姓名和密码,n
而无需在任何命令的任何命令行上传递任何密码。
该paste
实用程序将多个文件作为列粘合在一起,并在它们之间插入分隔符。在这里,我们使用:
作为分隔符并给它两个“文件”(过程替换)。第一个包含seq
创建 20 个学生用户名的命令的输出,第二个包含创建 20 个长度为 13 的随机字符串的管道的输出。
如果您有一个已生成用户名的文件:
#!/bin/bash
n=$(wc -l <usernames.txt)
paste -d : usernames.txt \
<( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd
这些会将密码和用户名保存到文件中,secret.txt
而不是在终端中显示生成的密码。
答案2
echo
很可能内置于 shell 中,因此它不会ps
作为单独的进程出现。
但是您不需要使用命令替换,您可以直接将管道的输出直接发送到chpasswd
:
{ printf "%s:" "$username";
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''
} | chpasswd
如果您想通过一次运行更改多个密码chpasswd
,那么重复基本部分应该很容易。或者将其变成一个函数:
genpws() {
for user in "$@"; do
printf "%s:" "$user";
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13
echo
done
}
genpws username1 username2... | chpasswd
顺便说一句:这head /dev/urandom
感觉有点奇怪,因为urandom
不是面向线路的。它可能会从中读取过多的字节,这将影响内核的可用熵概念,进而可能导致/dev/random
阻塞。只读取固定数量的数据,并使用类似base64
将随机字节转换为可打印字符的方法(而不是仅仅扔掉获得的大约 3/4 字节)可能会更干净。
像这样的东西会给你大约。 16个字符和数字:
head -c 12 /dev/urandom | base64 | tr -dc A-Za-z0-9
(也就是说,在 的输出中减去+
和字符的数量。每个字符的概率为 1/32,所以如果我的组合正确,则大约有 99% 的机会留下至少 14 个字符,并且99.99% 的机会留下至少 12 个。)/
base64