在将后台子进程的输出写入 Python 中的文件之前修改它

问题描述 投票:0回答:1

我想使用 python 来执行 minic bash 命令

./script.sh &> /tmp/my.log &
,但是 Python 代码能够在将行写入输出文件之前对其进行修改。

import subprocess
import threading
import sys

log_file = sys.argv[1]
program_and_args = sys.argv[2:]

with open(log_file, 'w') as log:
    process = subprocess.Popen(program_and_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, start_new_session=True)
    print(f"Background process started. PID: {process.pid}")

    def capture_output():
        lineno = 1 # example, real logic more complicated
        for line in process.stdout:
            log.write(f'{lineno}: {line}')
            log.flush()
            lineno += 1
        process.wait()

    # capture_output()

    thread = threading.Thread(target=capture_output, daemon = True)
    thread.start()

print("Main program continuing...")

虽然上面的python程序可以运行如下。

./main.py /tmp/my.log ./script.sh

但是

/tmp/my.log
中什么也没写。如何修复 python 程序,使其具有与 bash 命令
./script.sh &> /tmp/my.log &
相同的效果,并且能够使用任意 Python 代码修改内容?

python subprocess
1个回答
0
投票

介绍词

以下解释假设您希望 Python 进程立即返回到父 shell,但继续在后台运行。这相当于在父 shell 中使用

&
,因为当父进程负责生成子进程时,它知道该子进程的 PID;但是自我守护让孩子产生了一个父母一无所知的孙子。 这是不好的做法,会导致痛苦和痛苦。不要这样做,尽管我将在下面向您展示如何操作。


为什么原来的代码失败了?

当您设置

daemon=True
时,您是在告诉 Python 解释器不要在该线程退出时关闭其退出。 当解释器关闭时,线程仍然会死亡。

要等待线程完成,请调用其

.join()
方法。


我怎样才能真正从Python创建一个守护进程?

大多数情况下,这与How to make a Python script run like a service or daemon in Linux - 请阅读它以获取涉及使用第3方库并尝试可移植的答案。

import os, sys, subprocess

# validate our arguments before daemonizing
log_file_name = sys.argv[1]
program_and_args = sys.argv[2:]

pid = os.fork()
if pid:
  print(f"Background Python process started. PID: {pid}", file=sys.stderr)
  sys.exit(0)

# overwrite stdin, stdout, and stderr with /dev/null so we can survive a terminal exit
# this makes us more like nohup than `&`, granted.
with open(os.devnull, 'w+') as devnull:
    devnull_fd = devnull.fileno()
    if os.isatty(0): os.dup2(devnull_fd, 0)
    if os.isatty(1): os.dup2(devnull_fd, 1)
    if os.isatty(2): os.dup2(devnull_fd, 2)

# No point to a with clause; we get closed when we exit
log_file = open(log_file_name, 'w')

process = subprocess.Popen(program_and_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)

lineno = 1 # example, real logic more complicated
for line in process.stdout:
    log_file.write(f'{lineno}: {line}')
    log_file.flush()
    lineno += 1

如果你希望你的 Python 进程创建一个线程以便它可以做其他事情,那很好——但是 不要使用

daemon=True
;您需要让该线程在退出之前完成。

© www.soinside.com 2019 - 2024. All rights reserved.