过滤掉Python子进程模块中需要终端的命令

2023-12-25

我正在开发一个机器人,它接受来自网络(XMPP)的命令,并使用Python中的子进程模块来执行它们并发回命令的输出。本质上它是一个类似 SSH 的基于 XMPP 的非交互式 shell。

机器人仅执行来自经过身份验证的可信源的命令,因此允许任意 shell 命令(shell=True).

然而,当我不小心发送一些需要 tty 的命令时,机器人被卡住了。

例如:

subprocess.check_output(['vim'], shell=False)
subprocess.check_output('vim', shell=True)

如果收到上述每个命令,机器人就会被卡住,并且运行机器人的终端就会损坏。

尽管机器人只接收来自经过身份验证的可信来源的命令,但人类还是会犯错。我怎样才能让机器人过滤掉那些会破坏自身的命令?我知道有os.isatty但我该如何利用它呢?有没有办法检测那些“坏”命令并拒绝执行它们?

TL;DR:罢工>

比如说,有两种命令:

  • 命令如ls: 不需要 tty 来运行。
  • 命令如vim: 需要一个 tty;如果没有给出 tty,则中断子进程。

我怎么知道一个命令是ls- 类似或是vim-like 并拒绝运行命令(如果是)vim-like?


您期望的是一个接收命令作为输入并返回的函数有意义的通过运行命令输出。

由于命令是任意的,对 tty 的要求只是可能发生的许多不良情况之一(其他包括运行无限循环),您的函数应该只关心它的运行周期,换句话说,命令是“坏”还是不应该取决于它是否在有限时间内结束,并且因为subprocess本质上是异步的,您可以只运行命令并在更高的视野中处理它。

演示代码播放,可以更改cmd值来看看它的表现有何不同:

#!/usr/bin/env python
# coding: utf-8

import time
import subprocess
from subprocess import PIPE


#cmd = ['ls']
#cmd = ['sleep', '3']
cmd = ['vim', '-u', '/dev/null']

print 'call cmd'
p = subprocess.Popen(cmd, shell=True,
                     stdin=PIPE, stderr=PIPE, stdout=PIPE)
print 'called', p

time_limit = 2
timer = 0
time_gap = 0.2

ended = False
while True:
    time.sleep(time_gap)

    returncode = p.poll()
    print 'process status', returncode

    timer += time_gap
    if timer >= time_limit:
        print 'timeout, kill process'
        p.kill()
        break

    if returncode is not None:
        ended = True
        break

if ended:
    print 'process ended by', returncode

    print 'read'
    out, err = p.communicate()
    print 'out', repr(out)
    print 'error', repr(err)
else:
    print 'process failed'

上述代码中值得注意的三点:

  1. We use Popen代替check_output运行命令,与check_output这将等待该过程结束,Popen立即返回,因此我们可以做进一步的事情来控制过程。

  2. 我们实现一个计时器来检查进程的状态,如果它运行太长时间,我们手动杀死它,因为我们认为如果一个进程不能在有限的时间内结束,它就没有意义。这样你原来的问题就解决了,如下vim永远不会结束,它肯定会被作为一个“无意义”的命令而被杀死。

  3. 定时器帮助我们过滤掉坏命令后,我们可以通过调用来获取命令的stdout和stderrcommunicate的方法Popen对象,之后您可以选择确定返回给用户的内容。

结论

不需要tty模拟,我们应该异步运行子进程,然后通过定时器控制它来确定是否应该杀死它,对于正常结束的,它是安全且容易获得输出的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

过滤掉Python子进程模块中需要终端的命令 的相关文章

随机推荐