SIGUSR1信号在tar中异常失效:进程被终止而非返回进度
问题原因及解决方法
核心原因分析
1. shell=True导致信号误发给shell进程
如果你的Python代码用shell=True启动tar,实际运行的是shell进程(bash/sh),tar只是shell的子进程。此时调用process.send_signal()或os.killpg()会把信号发给shell,而shell默认没有处理SIGUSR1的逻辑,会直接终止。shell终止时会向子进程发送SIGHUP信号,导致tar也跟着终止(返回码-10对应SIGUSR1,实际是shell被该信号杀死)。
而用subprocess.Popen(["pkill", "-SIGUSR1", "tar"])时,信号是直接匹配tar进程发送的,tar能正确识别并处理,不会终止。
2. 环境变量缺失导致信号处理崩溃
如果Python进程运行在非终端环境(比如后台脚本),子进程的TERM环境变量可能缺失。GNU tar在收到SIGUSR1输出进度时,需要TERM确定终端输出格式,缺失该变量可能导致tar崩溃,表现为收到信号后直接终止。
3. 信号发送时机过早
如果在tar完成初始化、安装好SIGUSR1处理函数之前发送信号,tar会触发默认的信号处理逻辑而终止。
解决方法
方法1:避免使用shell=True,直接启动tar进程
用列表形式传递命令参数,此时process.pid就是tar进程的PID,信号会直接发送给tar:
import subprocess import signal import time # 直接启动tar进程,无需shell process = subprocess.Popen(["tar", "-xpf", "archive.tar", "--totals=SIGUSR1", "./blah"]) time.sleep(1) # 等待tar完成初始化 process.send_signal(signal.SIGUSR1) # tar会输出进度到stderr,进程不会终止
方法2:若必须用shell=True,找到tar的真实PID再发信号
通过父进程PID(shell的PID)找到tar的PID,直接向tar发送信号:
import subprocess import signal import time import os process = subprocess.Popen("tar -xpf archive.tar --totals=SIGUSR1 ./blah", shell=True) time.sleep(1) # 获取shell的子进程(即tar)的PID tar_pid = int(subprocess.check_output(["pgrep", "-P", str(process.pid)]).strip()) os.kill(tar_pid, signal.SIGUSR1)
方法3:补充缺失的环境变量
给子进程设置TERM环境变量,确保tar能正常输出进度:
import subprocess import signal import time import os env = os.environ.copy() env["TERM"] = "xterm" # 模拟终端环境 process = subprocess.Popen(["tar", "-xpf", "archive.tar", "--totals=SIGUSR1", "./blah"], env=env) time.sleep(1) process.send_signal(signal.SIGUSR1)
内容的提问来源于stack exchange,提问作者Xevion
相关产品推荐
相关产品推荐

