在cron或rc.local中运行python子进程时捕获stdout和stderr

2 投票
1 回答
2369 浏览
提问于 2025-04-18 17:59

我在用cron或rc.local启动一个命令时,遇到了无法访问输出(错误输出和标准输出)的问题。

在普通的命令行中运行是没问题的,但通过rc.local就不行了。

cat /root/watchdog.py 
import subprocess
    cmd = ( 'echo "TEST" |gnokii --config /root/.config/gnokii/config --sendsms +123456789xx ')
    #p = subprocess.Popen([cmd, '2>&1'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
    p = subprocess.Popen([cmd, '2>&1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    output = p.stdout.read()
    output += p.stderr.read()
    logFile = open("/root/logfile", 'a+')
    ##### 
    #Idea to read line by line:
    #output = ''
    #    for line in iter(p.stdout.readline,''):
    #       print "captured line: %s" % line.rstrip()
    #       #logFile.write(line.rstrip())
    #       output += line
    logFile.write(output)
    logFile.close()

从控制台运行时的输出看起来是这样的:

/root/watchdog.py 
GNOKII Version 0.6.30
Cannot open logfile /root/.cache/gnokii/gnokii-errors
WARNING: cannot open logfile, logs will be directed to stderr
Send succeeded with reference 186!

在我的rc.local文件中

/root/watchdog.py  > /root/mywatchPY.out 2>&1 & 

这看起来很有意思:将子进程的错误输出重定向到标准输出,但这并没有解决我的问题。

有没有办法在没有完整命令行的情况下捕获子进程的错误输出和标准输出呢?

1 个回答

1

你的代码里有几个问题:

  • 当你使用 shell=True 时,命令和它的参数应该作为一个字符串传入。否则,参数会被传给命令行,而不是传给你想执行的命令。
  • 如果你想把错误信息和正常输出合并在一起,应该用 stderr=subprocess.STDOUT,而不是 2>&1,这样可以确保整个流程都适用,而不仅仅是最后一个命令。
  • 应该使用 p.communicate(),而不是 p.stdout.read()p.stderr.read(),否则如果操作系统的管道缓冲区满了,子进程可能会卡住。
  • 如果你想把输出重定向到一个文件里,那么你不需要先把它保存为字符串。
import shlex
from subprocess import Popen, PIPE, STDOUT

with open("/root/logfile", 'ab', 0) as logfile:
    p = Popen(shlex.split('gnokii ... +123456789xx'), 
              stdin=PIPE, stdout=logfile, stderr=STDOUT)
    p.communicate(b'TEST')

将子进程的错误输出重定向到标准输出 这个问题不适用,因为你已经明确地重定向了 stdout

撰写回答