You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本subprocess调用C程序作为systemctl服务运行失败

问题:Systemd服务运行Python脚本时调用C程序无输出导致报错

我是技术新手,还请包涵。我在树莓派的Ubuntu Server 22.04上写了个Python脚本,按下遥控器按键时会通过subprocess调用一个C程序,这个C程序用来测量音频信号采样率,以二进制形式把值传给Python脚本,Python拿到值后乘以10再做后续处理。相关Python代码如下:

def oled_stringSR():
    a = subprocess.run("gcc freq_count_2.c -lpigpio -lrt -o out1;./out1", capture_output = True, shell = True)
    d = 10*int(a.stdout)
    if d < 40001:
        sample_rate = 32
    elif 40000 < d < 46001:
        sample_rate = 44.1

用sudo在终端运行脚本一切正常,但做成systemctl服务运行,触发遥控器逻辑时脚本就挂了,journalctl里的报错是:

May 17 23:19:00 raspcamilla oled[1076]: Traceback (most recent call last):
May 17 23:19:00 raspcamilla oled[1076]:   File "/home/marcosch/remote.py", line 2231, in <module>
May 17 23:19:00 raspcamilla oled[1076]:     main()
May 17 23:19:00 raspcamilla oled[1076]:   File "/home/marcosch/remote.py", line 1267, in main
May 17 23:19:00 raspcamilla oled[1076]:     oled_stringSR()
May 17 23:19:00 raspcamilla oled[1076]:   File "/home/marcosch/remote.py", line 2084, in oled_stringSR
May 17 23:19:00 raspcamilla oled[1076]:     d = 10*int(a.stdout)
May 17 23:19:00 raspcamilla oled[1076]: ValueError: invalid literal for int() with base 10: b''

看起来是C程序没运行或者没输出,而且我不用sudo在终端跑脚本也会出一模一样的错,怀疑是权限问题。我知道systemd服务一般以root身份运行,这到底是为啥?

当前的systemd服务文件如下:

[Unit]
After=syslog.target
StartLimitIntervalSec=10
StartLimitBurst=10

[Service]
Type=simple
ExecStart=python3 /home/marcosch/remote.py
Restart=always
RestartSec=1
StandardOutput=journal
StandardError=journal
SyslogIdentifier=oled
User=root
Group=root

[Install]
WantedBy=graphical.target

问题分析与解决办法

核心原因

虽然服务配置了以root运行,但systemd服务的默认工作目录是根目录/,不是你脚本所在的/home/marcosch/。你的subprocess命令直接编译运行freq_count_2.c和out1,在根目录下找不到这些文件,自然编译失败、没有输出,导致Python解析空字符串报错。

另外还有几个潜在问题:

  1. 每次触发都重新编译C程序,效率极低且易产生冗余文件
  2. 未捕获subprocess的错误输出,无法排查编译/运行失败的具体原因
  3. 服务的WantedBy=graphical.target在无图形界面的Ubuntu Server环境下,可能无法自动启动

解决步骤

1. 预编译C程序,避免重复编译

在终端用sudo编译好程序:

cd /home/marcosch
sudo gcc freq_count_2.c -lpigpio -lrt -o out1
sudo chmod +x out1

2. 修改Python脚本的subprocess调用

指定程序绝对路径,同时添加错误处理方便排查:

import sys
import subprocess

def oled_stringSR():
    # 调用预编译好的程序,用绝对路径
    a = subprocess.run("/home/marcosch/out1", capture_output=True, shell=False)
    
    # 先检查命令执行状态
    if a.returncode != 0:
        print(f"C程序运行失败,错误信息: {a.stderr.decode('utf-8')}", file=sys.stderr)
        return
    
    # 处理输出,先去除空白字符再判断是否为空
    stdout_str = a.stdout.decode('utf-8').strip()
    if not stdout_str:
        print("C程序无输出", file=sys.stderr)
        return
    
    try:
        d = 10 * int(stdout_str)
    except ValueError as e:
        print(f"解析输出失败: {e},输出内容: {stdout_str}", file=sys.stderr)
        return
    
    if d < 40001:
        sample_rate = 32
    elif 40000 < d < 46001:
        sample_rate = 44.1
    # 后续逻辑...

3. 修改systemd服务文件

  • 指定工作目录到脚本所在路径
  • 把WantedBy改为multi-user.target(适配无图形的Server环境)

修改后的服务文件:

[Unit]
After=syslog.target network.target
StartLimitIntervalSec=10
StartLimitBurst=10

[Service]
Type=simple
WorkingDirectory=/home/marcosch
ExecStart=python3 /home/marcosch/remote.py
Restart=always
RestartSec=1
StandardOutput=journal
StandardError=journal
SyslogIdentifier=oled
User=root
Group=root

[Install]
WantedBy=multi-user.target

4. 重新加载服务并重启

sudo systemctl daemon-reload
sudo systemctl restart oled.service

额外排查点

如果问题依旧,用以下命令查看服务详细日志,包括C程序的错误输出:

journalctl -u oled.service -f

内容的提问来源于stack exchange,提问作者MrRamone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:40:42