/etc/rc.local(通过 systemd 运行)在 cat'ing /dev/urandom 时挂起

Dan*_*ell 1 startup scripts systemd

我创建了一个/etc/rc.local

$ cat /etc/rc.local 
#!/bin/bash

echo "Starting"
randomString=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`
echo "Finished"
Run Code Online (Sandbox Code Playgroud)

这在交互式运行时运行:

$ /etc/rc.local 
Starting
Finished: lkFcvByNaIu7zmxuCYB3BQmJ05LwuVWL
Run Code Online (Sandbox Code Playgroud)

但是,当从 systemd 运行时,它会挂起并且不会返回。

如果我 ctrl+C 看起来它挂在fold命令上:

$ systemctl status rc-local
? rc-local.service - /etc/rc.local Compatibility
   Loaded: loaded (/lib/systemd/system/rc-local.service; enabled-runtime; vendor preset: enabl
  Drop-In: /lib/systemd/system/rc-local.service.d
           ??debian.conf
   Active: activating (start) since Mon 2019-03-11 12:04:06 UTC; 12s ago
     Docs: man:systemd-rc-local-generator(8)
Cntrl PID: 936 (rc.local)
    Tasks: 5 (limit: 1152)
   CGroup: /system.slice/rc-local.service
           ??936 /bin/bash /etc/rc.local start
           ??952 /bin/bash /etc/rc.local start
           ??953 cat /dev/urandom
           ??954 tr -dc a-zA-Z0-9
           ??955 fold -w 32

Mar 11 12:04:06 ip-10-0-4-116 systemd[1]: Starting /etc/rc.local Compatibility...
Mar 11 12:04:06 ip-10-0-4-116 rc.local[936]: Starting
Run Code Online (Sandbox Code Playgroud)
$ ps -ef
root       936     1  0 12:04 ?        00:00:00 /bin/bash /etc/rc.local start
root       952   936  0 12:04 ?        00:00:00 /bin/bash /etc/rc.local start
root       953   952 47 12:04 ?        00:00:23 cat /dev/urandom
root       954   952 36 12:04 ?        00:00:18 tr -dc a-zA-Z0-9
root       955   952 10 12:04 ?        00:00:05 fold -w 32
Run Code Online (Sandbox Code Playgroud)

解决方法(各种)

我真的不需要一个非常随机的字符串,所以我可以使用:

date | md5sum | cut -c -12
Run Code Online (Sandbox Code Playgroud)

生成一个字符串。这在由 systemd 运行时工作正常。但是知道为什么前面的命令会挂起会很有趣。

gmt*_*t42 6

担!

恕我直言,cat /dev/urandom一定会永远持续下去,所以你应该使用一个命令先读取八十行随机内容,然后关闭输入。

使用简单的head -80您仍然有多余的字符不使用,但它不应该永远停止,因为它在 80 个换行符(或 CRLF)后关闭/dev/urandom。这是一个丑陋的黑客:

$ cat /etc/rc.local 
#!/bin/bash

echo "Starting"
randomString=`head -80 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1`
echo "Finished"
Run Code Online (Sandbox Code Playgroud)

恕我直言,后台任务中的行为是不同的,因为 systemd 不知道 cat /dev/urandom何时会完成从随机数设备的读取。看起来是一样的,但很明显,它不是。一旦最后一个 head 命令完成,您的脚本就依赖于中断管道,因此可移植性不可靠。它还可以以管道中先前命令已捕获并处理的“Broken Pipe”信号结束。在 systemd 运行的 init 脚本中,可能没有提供这种通信,并且cat /dev/urandom挂起,因为它没有收到SIGPIPE信号或其他东西......

希望这可以帮助。

这并不能保证[A-Za-z0-9]范围内的 32 个字符,但重点是关闭/dev/urandom而不是依靠SIGPIPE魔法来终止进程,这在后台似乎无法正常工作,没有控制终端。

你也可以这样做:

randomString=`head -80 /dev/urandom | md5sum | cut -c -12`
Run Code Online (Sandbox Code Playgroud)

就像你的第二个例子一样。它是随机的/dev/urandom