python 执行 shell 命令卡死

本文介绍了一个Python特有的问题,在Python中调用shell命令时可能会遇到卡死的情况,尤其是在涉及管道通信时。文章详细分析了问题产生的原因,并提供了解决方案。
部署运行你感兴趣的模型镜像

最近发现了一个 python 特有的卡死问题,是通过 python 调用 shell 命令出现的,特此记录一下。

 

1、问题描述

这里我用一个例子来进行说明,并非真实使用场景。

 

1.1、普通 shell 命令执行:

yes yes | echo 'hello'

在 shell 中能够正常结束并输出。

 

1.2、python 调用 shell 命令执行:

import osos.system("yes yes | echo 'hello'")

但在 python 中会卡死,用其他调用函数或者换 subprocess 模块也一样。

 

1.3、yes 进程

这里也解释一下 yes 进程的作用,一些命令可能需要手动输入 ‘yes’ 来告知选择,但不方便自动化,所以利用 yes 进程不断地输出 ‘yes’ 来自动填。

 

2、问题分析&解决

 

2.1、管道

yes "yes" | $(其他命令)

‘|’其实是管道符号,前后两句命令其实是通过管道通信的,

即前面命令的结果写入管道,而后面命令从管道中读取数据作为输入。

 

管道遵循 FIFO 的使用方式

由于 yes 进程是不断地输出的,命令执行时间为无限(若不从外部中止);

而此时其他命令执行时间短,这时候管道的读端已经关闭,

这时 yes 进程再想写入管道的时候,内核立刻将 SIGPIPE 发送给 yes 进程,SIGPIPE 默认行为是终止进程。

/* write on a pipe with no one to read it */#define        SIGPIPE        13

也即术语:管道破裂

管道破裂,这个信号通常在进程间通信产生,比如采用 FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到 SIGPIPE 信号.  -- 维基百科

 

2.2、python 问题

那为什么 shell 执行不会卡死,通过 python 调用 shell 命令反而卡死了呢?

On Unix, Python sets SIGPIPE to SIG_IGN on startup, because it prefers to check every write and raise an IOError exception rather than taking SIGPIPE. 

Python 为了自己能处理写入错误,报告异常,启动时就把 SIGPIPE 设置为忽略状态。

但是对于非 python 的类 Unix 中的子进程,是靠 SIGPIPE 进行通信的。

如果不采用 SIGPIPE 的话,就需要自己检查系统调用 write 返回的 EPIPE。

 

2.3、如何解决​​​​​​​

import signal# 恢复为默认状态signal.signal(signal.SIGPIPE, signal.SIG_DFL)

 

3、结论

使用 python 调用子进程执行 bash 语句要注意管道破裂问题,为保安全,可以先设置信号为默认状态。

 

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值