我有一个运行基于 Debian 的 Linux 发行版的微控制器。
我有一个 Nextion 屏幕,通过 /dev/ttyMOD1 端口上的 UART 连接到它。我有一个脚本,它使用 stty,并使用 cat 从屏幕获取数据并将其输出到 mqtt 主题。当我从 shell 运行脚本,或者在系统启动后重启服务时,我能够通过 ssh 连接,它运行正常。但是,当系统启动时,服务内部的 cat 任务由于某种原因无法运行,只有在服务重启后才能运行。
脚本和服务文件对用户具有 +x 权限。我需要帮助来解决 cat 在启动时无法运行的问题。
脚本和服务的文本:
serial.service
[Unit]
Description=Serial script on startup
Requires=wb-mqtt-serial.service
After=wb-mqtt-serial.service
[Service]
User=root
WorkingDirectory=/mnt/data/root
ExecStart=/mnt/data/root/serial.sh
Restart=on-failure
Type=simple
[Install]
WantedBy=multi-user.target
serial.sh
#!/bin/bash
mqtt-delete-retained "/devices/screen/#"
stty -F /dev/ttyMOD1 ospeed 9600 ispeed 9600 raw clocal -parenb -echo cs8
CR="$(echo -e '\r')"
exec 4<> /dev/ttyMOD1
/bin/cat <&4 | while :
do
IFS="$CR" read -r line
case "$line" in quit*)
break
;;
*)
if [[ -n "$line" ]]; then
mosquitto_pub -t /devices/screen/controls/raw/meta/type -r -m text
mosquitto_pub -t /devices/screen/controls/raw -r -m "$line"
fi
;;
esac
done
ttyMOD1
出现问题的最明显方式是,如果服务在可用之前尝试启动;这会导致cat
失败,但由于即使失败,循环仍会继续进行read
,管道运算符右侧的进程不知道cat
失败并继续尝试运行,从而阻止Restart=on-failure
服务配置中的指令产生任何效果。您可以向 systemd 服务定义添加一些额外的依赖项和排序指令:
...告诉 systemd 稍后再启动它,等到它更有可能成功的时候(
After=network-online.target
如果 mqtt 命令在没有网络的情况下无法运行,你可能也需要这个选项)。(这BindTo=
告诉 systemd,如果设备消失后又恢复,你的服务将需要重新启动)。为确保在满足依赖关系之前运行脚本时系统能够恢复,请考虑:
笔记:
read
时让它死亡但失败。cat
stty
;同样,这可以防止脚本卡在损坏但仍在运行的状态。cat
我们这里根本不使用,而是read
直接从设备中使用。