【问题标题】:Python subprocess.Popen PIPE and SIGPIPEPython subprocess.Popen PIPE 和 SIGPIPE
【发布时间】:2018-06-08 16:01:25
【问题描述】:

当我浏览帖子时,我在here 上遇到了以下示例,它说需要调用proc1.stdout.close() 才能正确退出proc1,生成SIGPIPE

import subprocess

proc1 = subprocess.Popen(['ps', 'cax'], stdout=subprocess.PIPE)
proc2 = subprocess.Popen(['grep', 'python'], stdin=proc1.stdout,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)

proc1.stdout.close() # Allow proc1 to receive a SIGPIPE if proc2 exits.
out, err = proc2.communicate()
print('out: {0}'.format(out))
print('err: {0}'.format(err))

但是,我不清楚这一点。请修正我的理解。

  1. SIGPIPE 发生在 PIPE 尝试写入已关闭的 PIPE 时。
  2. 作者PIPEproc1stdout,读者PIPEproc2stdin
  3. proc2 退出并且proc1 尝试将数据写入proc2stdin PIPE 时,proc1 将退出。 因为
    • proc2stdin PIPEproc2 退出时关闭
    • SIGPIPE 发生在 proc1,因为 proc1 尝试写入已关闭的 proc2stdin PIPE

根据我的理解,SIGPIPE 会发生并且proc1 会退出,无论是否关闭proc1stdout

我错过了什么?


编辑

从@unutbu 的评论中阅读post 后......

我认为复制的文件描述符(proc1.stdout)是写入器管道,而不是读取器管道。因此,有两个写入器 PIPE 和一个读取器 PIPE 相互连接。

因此,proc2 退出时会生成SIGPIPE,因为proc2 只是一个拥有读卡器PIPE 的进程(proc2 退出时将关闭)。

但是,上面的post 似乎通过复制proc1.stdout 表示有两个读取器PIPE,因此即使在proc2 退出后也不会生成SIGPIPE,因为还有另一个读取器PIPE 打开。以下是post的部分。

因此,通过立即关闭 p1.stdout,您可以确保唯一的 从 dmesg stdout 读取的剩余文件句柄是 grep 进程, 如果该进程退出,dmesg 会收到一个 SIGPIPE。

我并不是说post 是错误的,但我只是想修正我的理解。提前谢谢你。

【问题讨论】:

标签: python linux subprocess pipe sigpipe


【解决方案1】:
proc1 = subprocess.Popen(['ps', 'cax'], stdout=subprocess.PIPE)

在父进程和proc1之间创建一个管道:

|        |         |       |
| parent |-<-----<-| proc1 |                   
|        | ^       |       |
           |                     
       p1.stdout   

p1.stdout 是父级读取以从proc1 获取(标准输出)输出的内容。

proc2 = subprocess.Popen(['grep', 'python'], stdin=proc1.stdout,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)

将管道的副本从 proc1 连接到 proc2:

|        |         |       |         |       |
| parent |-<-----<-| proc1 |->----->-| proc2 | 
|        |         |       |         |       |

通过调用p1.stdout.close(),我们关闭了父进程的管道:

|        |         |       |         |       |
| parent |       <-| proc1 |->----->-| proc2 | 
|        |         |       |         |       |

现在当proc2 终止时,它的管道一侧也关闭了:

|        |         |       |         |       |
| parent |       <-| proc1 |->       | proc2 | 
|        |         |       |         |       |

下次proc1 尝试写入管道时,会生成一个 SIGPIPE 信号, 这允许proc1 终止,因为它知道没有人在其管道的另一端监听。

【讨论】:

  • 非常感谢!!我明白了。我似乎误解了subprocess.PIPE
  • 这听起来很基础,但第一个命令中的父进程是什么?
  • @pankajmishra:父进程是运行python脚本的进程——调用subprocess.Popen的进程。
  • 好的。谢谢你的回答
猜你喜欢
  • 2011-01-06
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-20
  • 2013-05-22
  • 2011-11-26
  • 2015-07-19
相关资源
最近更新 更多