当ssh管道坏了时停止python程序

use*_*424 6 python linux ssh

我正在编写一个带有无限循环的python脚本,我在ssh上运行.当某人杀死ssh时,我希望脚本终止.例如:

脚本(script.py):

while True:
    # do something
Run Code Online (Sandbox Code Playgroud)

将运行为:

ssh foo ./script.py
Run Code Online (Sandbox Code Playgroud)

当我杀死ssh进程时,我希望另一端的脚本停止运行.

我试过寻找一个封闭的标准输出:

while not sys.stdout.closed:
    # do something
Run Code Online (Sandbox Code Playgroud)

但这没用.

我该如何实现这一目标?

编辑:

远程机器是Mac,它在csh中打开程序:

502 29352 ??         0:00.01 tcsh -c python test.py
502 29354 ??         0:00.04 python test.py
Run Code Online (Sandbox Code Playgroud)

我正在从python脚本中打开ssh进程,如下所示:

p = Popen(['ssh','foo','./script.py'],stdout=PIPE)

while True:
    line = p.stdout.readline()
    # etc
Run Code Online (Sandbox Code Playgroud)

编辑

提议的解决方案:

  1. 运行脚本 while os.getppid() != 1

这似乎在Linux系统上工作,但并没有在远程机器运行OSX时工作.问题是该命令是在csh中启动的(见上文),因此csh的父进程id设置为1,而不是脚本.

  1. 定期登录 stderr

这有效,但脚本也在本地运行,我不想打印心跳stderr.

  1. 用pseduo tty运行脚本ssh -tt.

这确实有效,但有一些奇怪的后果.考虑以下:

remote_script:

#!/usr/bin/env python
import os
import time
import sys

while True:
    print time.time()
    sys.stdout.flush()
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

local_script:

#!/usr/bin/env python
from subprocess import Popen, PIPE
import time

p = Popen(['ssh','-tt','user@foo','remote_script'],stdout=PIPE)

while True:
    line = p.stdout.readline().strip()
    if line:
        print line
    else:
        break
    time.sleep(10)
Run Code Online (Sandbox Code Playgroud)

首先,输出真的很奇怪,它似乎不断添加标签或东西:

[user@local ~]$ local_script 
1393608642.7
            1393608643.71
                         1393608644.71
                                      Connection to foo closed.
Run Code Online (Sandbox Code Playgroud)

其次,程序在第一次收到时不会退出SIGINT,即我必须按两次Ctrl-C才能杀死local_script.

bru*_*ard 6

好的,我有一个解决方案

当ssh连接关闭时,父进程id将从ssh-deamon的pid(处理连接的fork)更改为1.

因此,以下解决了您的问题.

#!/usr/local/bin/python

from time import sleep
import os

#os.getppid() returns parent pid
while (os.getppid() != 1):
    sleep(1)
    pass
Run Code Online (Sandbox Code Playgroud)

你能否证实这也适合你:)

编辑

我看到你更新了.

这没有经过测试,但为了让这个想法适用于OSX,您可能能够检测到csh更改的过程.以下代码仅说明了一个想法,尚未经过测试.这说我认为它会起作用,但它不会是最优雅的解决方案.如果signals可以找到使用跨平台的解决方案,那将是首选.

def do_stuff():
    sleep(1)

if sys.platform == 'darwin':
    tcsh_pid = os.getppid()
    sshfork_pid = psutil.Process(tcsh_pid).ppid
    while (sshfork_pid == psutil.Process(tcsh_pid).ppid)
       do_stuff()

elif sys.platform == 'linux':
    while (os.getppid() != 1):
        sleep(1)
else:
    raise Exception("platform not supported")

sys.exit(1)
Run Code Online (Sandbox Code Playgroud)


Cha*_*ffy 2

我建议定期登录到 stderr。

当您不再有可写入的 stderr 时,这将导致发生异常。