我正在尝试使用systemd执行shell脚本。
如果我从bash运行我的脚本一切正常。但是,如果我通过systemd运行相同的脚本,它永远不会完成。似乎挂起的命令是:
random="$(LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w128 | head -n1)"
如果我用random="1234"
替换此行,它也会运行systemd。我猜'悬挂'命令是tr
- 它的过程永远不会完成。
这是我正在使用的systemd单元文件:
[Unit]
Description=my script
[Service]
Type=forking
Restart=on-failure
ExecStart=/mypath/script.sh start
ExecStop=/bin/kill $MAINPID
ExecStopPost=/bin/rm -f /mypath/RUNNING_PID
[Install]
WantedBy=multi-user.target
答案 0 :(得分:5)
编辑:使解释更加清晰并添加新信息。
简短回答:在IgnoreSIGPIPE=false
文件的[Service]
下设置.service
。来自systemd.exec
手册:
IgnoreSIGPIPE= Takes a boolean argument. If true, causes SIGPIPE to be ignored in the executed process. Defaults to true because SIGPIPE generally is useful only in shell pipelines.
长解释:
random =&#34; $(LC_ALL = C tr -cd&#39; [:alnum:]&#39;&lt; / dev / urandom | fold -w128 | 头-n1)&#34;
当head
命令从fold
收到第一个换行符后退出时,它的打开文件描述符将被关闭。当fold
命令稍后尝试写入管道时,它将收到SIGPIPE
信号。此信号的默认操作是终止该过程。这通常应该导致fold
命令的终止,同样随后终止tr
命令。
但是,当管道在systemd
下运行时,systemd
会将SIGPIPE
的默认操作设置为SIG_IGN
,这会使管道中的进程忽略该信号。虽然fold
命令忽略该信号,但在写入损坏的管道时仍会收到EPIPE错误。但是fold
命令不检查任何fwrite
调用的返回值,至少不在coreutils-8.26
中。这导致fold
命令继续从std中读取并忽略错误,写入std out。这样做时,fold
会使tr
的管道保持打开状态。由于tr
也忽略了SIGPIPE
,并且fold
的管道已打开,它只是继续从/dev/urandom
读取并将过滤后的字节永久写入管道。