我想使用 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 进程立即返回到父 shell,但继续在后台运行。这不相当于在父 shell 中使用
&
,因为当父进程负责生成子进程时,它知道该子进程的 PID;但是自我守护让孩子产生了一个父母一无所知的孙子。 这是不好的做法,会导致痛苦和痛苦。不要这样做,尽管我将在下面向您展示如何操作。
当您设置
daemon=True
时,您是在告诉 Python 解释器不要在该线程退出时关闭其退出。 当解释器关闭时,线程仍然会死亡。
要等待线程完成,请调用其
.join()
方法。
大多数情况下,这与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
;您需要让该线程在退出之前完成。