gpt4 book ai didi

python - 如何为在 pty 下运行的进程设置终端前台进程组?

转载 作者:太空狗 更新时间:2023-10-29 22:23:03 24 4
gpt4 key购买 nike

我编写了一个简单的包装器脚本,用于在命令失败时重复命令,称为 retry.py .但是,因为我想查看子命令的输出,所以我不得不使用一些 pty 技巧。这适用于 rsync 等程序,但 scp 等其他程序应用额外测试来显示进度表等内容。

scp 代码有一个广泛的测试:

getpgrp() == tcgetpgrp(STDOUT_FILENO);

当我运行包装器脚本时失败。正如您在我的简单 tty_test.c 测试用例中看到的那样:

./tty_tests
isatty reports 1
pgrps are 13619 and 13619

和:

./retry.py -v -- ./tty_tests
command is ['./tty_tests']
isatty reports 1
pgrps are 13614 and -1
child finished: rc = 0
Ran command 1 times

我已经尝试使用 tcsetpgrp(),它最终作为 pty fd 上的 IOCTL,但会导致 pty 的 -EINVAL。如果可能的话,我宁愿继续使用 Python 子进程机制,还是需要手动 fork/execve?

最佳答案

如果您不需要为子进程提供全新的 pty,我相信您可以将程序缩减为:

from argparse import ArgumentParser
import os
import signal
import subprocess
import itertools

# your argumentparser stuff goes here

def become_tty_fg():
os.setpgrp()
hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN)
tty = os.open('/dev/tty', os.O_RDWR)
os.tcsetpgrp(tty, os.getpgrp())
signal.signal(signal.SIGTTOU, hdlr)

if __name__ == "__main__":
args = parser.parse_args()

if args.verbose: print "command is %s" % (args.command)
if args.invert and args.limit==None:
sys.exit("You must define a limit if you have inverted the return code test")

for run_count in itertools.count():
return_code = subprocess.call(args.command, close_fds=True,
preexec_fn=become_tty_fg)
if args.test == True: break
if run_count >= args.limit: break
if args.invert and return_code != 0: break
elif not args.invert and return_code == 0: break

print "Ran command %d times" % (run_count)

setpgrp() 调用在同一个 session 中创建一个新进程组,这样新进程将接收来自用户的任何 ctrl-c/ctrl-z/等,以及您的重试脚本惯于。然后 tcsetpgrp() 使新进程组成为控制 tty 上的前台进程组。当发生这种情况时,新进程会得到一个 SIGTTOU(因为自 setpgrp() 以来,它一直在后台进程组中),这通常会使进程停止,所以这就是忽略 SIGTTOU 的原因。我们将 SIGTTOU 处理程序设置回之前的状态,以尽量减少子进程被意外信号表混淆的可能性。

由于子进程现在位于 tty 的前台组中,它的 tcgetpgrp() 和 getpgrp() 将是相同的,并且 isatty(1) 将为真(假设它从 retry.py 继承的标准输出实际上是一个终端)。您不需要代理子进程和 tty 之间的流量,这样您就可以放弃所有的 select 事件处理和 fcntl-nonblocking-setting。

关于python - 如何为在 pty 下运行的进程设置终端前台进程组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15200700/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com