如何让systemd服务中Shell脚本调用的Python程序输出到Linux终端
问题
我用这段Python代码往树莓派的Linux控制台输出内容:
print("test1") sys.stdout.write("test2") sys.stdout.flush()
直接通过systemd服务运行这个Python程序时,输出能正常显示;但把Python程序放到Shell脚本里,再用systemd执行脚本,就看不到print()的输出了。
相关配置:
systemd服务文件
[Unit] Description=Kodi Service After=network-online.target Wants=network-online.target [Service] Type=forking User=root WorkingDirectory=/root/kodi/ ExecStart=/bin/bash /root/kodi/run_python.sh Restart=on-failure [Install] WantedBy=multi-user.target
run_python.sh脚本
#!/usr/bin/env bash python3 /root/kodi/validator.py
解决办法
问题根源
当Python程序通过Shell脚本被systemd调用时,print()的输出会因为标准输出缓冲机制或者systemd的Type=forking配置,导致内容无法正常传递到控制台。sys.stdout.write()加flush()能显示是因为手动强制刷新了缓冲区,而print()默认在非交互式终端(比如systemd启动的环境)下会采用全缓冲,内容不会立即输出。
方案1:调用Python时禁用缓冲
修改Shell脚本,给python3加上-u参数,强制关闭标准输出缓冲:
#!/usr/bin/env bash python3 -u /root/kodi/validator.py
-u参数会让Python的stdout和stderr变为无缓冲模式,确保print()的内容能实时输出。
方案2:调整systemd服务配置
- 将
Type=forking改为Type=simple:你的脚本和Python程序不会后台fork进程,forking类型不适用,simple能让systemd正确捕获程序输出。 - 添加输出配置,强制将内容同时发送到控制台和systemd日志:
修改后的systemd配置:
[Unit] Description=Kodi Service After=network-online.target Wants=network-online.target [Service] Type=simple User=root WorkingDirectory=/root/kodi/ ExecStart=/bin/bash /root/kodi/run_python.sh Restart=on-failure StandardOutput=journal+console StandardError=journal+console [Install] WantedBy=multi-user.target
方案3:修改Python代码的print行为
要么在每次调用print时加上flush=True:
print("test1", flush=True) sys.stdout.write("test2") sys.stdout.flush()
要么在代码开头重定义print函数,默认开启刷新:
import sys def print(*args, end='\n', flush=True): sys.stdout.write(' '.join(map(str, args)) + end) sys.stdout.flush()
验证
修改后执行以下命令重启服务:
systemctl daemon-reload systemctl restart kodi.service
此时控制台或通过journalctl -u kodi.service查看日志,就能看到test1和test2的输出了。
内容的提问来源于stack exchange,提问作者cheat.008
相关产品推荐
相关产品推荐

