1

所以我试图用python编写一个简单的包装器来调用rasa,一个nlu工具。我在命令行上写的命令是这样的:

curl -X POST "localhost:5000/parse" -d '{"q":"我在找他妈的墨西哥菜"}' | python -m json.tool

我期望的输出是这样的:

% Total % Received % Xferd 平均速度 时间 时间 当前 Dload 上传总花费 左速度 100 545 0 500 100 45 33615 3025 --:--:-- --:--:-- --:--:-- 35714

加上一个json文件的输出。

我用python写了这个程序:

import subprocess

utterance = "Lets say something"


result = subprocess.run(["curl", "-X", "POST", "localhost:5000/parse", "-d", "'{\"q\":\""+utterance+"\"}'", "|", "python", "-m", "json.tool"], stdout=subprocess.PIPE)
print(vars(result))
print(result.stdout.decode('utf-8'))

不幸的是,我的输出是这样的,这意味着我实际上并没有从 curl 调用中获得返回:

{'args': ['curl', '-X', 'POST', 'localhost:5000/parse', '-d', '\'{"q":"让我们说点什么"}\'', '|', 'python', '-m', 'json.tool'], 'returncode': 2, 'stdout': b'', 'stderr': 无}

如果我从命令行调用我的 python 程序,输出如下:

curl:选项 -m:需要一个正确的数字参数 curl:尝试 'curl --help' 或 'curl --manual' 获取更多信息 {'args': ['curl', '-X', 'POST', ' localhost:5000/parse', '-d', '\'{"q":"让我们说点什么"}\'', '|', 'python', '-m', 'json.tool'], 'returncode':2,'stdout':b'','stderr':无}

我试着到处寻找,但就是不能让它继续下去。非常感谢一些帮助。

4

1 回答 1

1

更新:我第一次严重误解了这个问题。匆忙阅读细节,所以我在那里道歉。您遇到了问题,因为您试图使用 Popen 将两个命令连接在一起。然而,管道运算符是由 shell 实现的,而不是 python。所以它期望你的命令只是一个与 curl 相关的命令。这很复杂,但你有选择。

我认为对于您的特定示例,最简单的方法是不要尝试将命令链接到 json.tool。你实际上不需要它。你已经在 python 中了,所以你可以漂亮地打印你自己从 curl 获得的输出。使用 python 看起来像

import json
import shlex
from subprocess import Popen, PIPE

command = 'curl -XGET http://localhost:9200'

p = Popen(shlex.split(command), stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate()

if p.returncode != 0:
    print(err)

j = json.loads(output.decode("utf-8"))
print(json.dumps(j, indent=4, sort_keys=True))

但是,如果您想要长期使用管道实际连接多个进程,那么这取决于场景。最简单的方法是传递shell=TruePopen传递确切的命令(不是参数列表)。这会将所有内容委托给 shell。我需要警告您,当命令基于用户输入时,这是非常可利用的2.x pipes.quote()3.x 都有shlex.quote()关于如何转义命令的建议,因此它应该是安全的。

from subprocess import Popen, PIPE

command = 'curl -XGET http://localhost:9200 | python -m json.tool'

p = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
output, err = p.communicate()

if p.returncode != 0:
    print(err)

print(output.decode("utf-8"))

因此,如果您发现自己需要连接进程但有一些基于用户输入的内容,您可以使用多个进程并自己连接它们。

import shlex
from subprocess import Popen, PIPE

command1 = 'curl -XGET http://localhost:9200'
command2 = 'python -m json.tool'

p1 = Popen(shlex.split(command1), stdout=PIPE)
p2 = Popen(shlex.split(command2), stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()
output, err = p2.communicate()

if p2.returncode != 0:
    print(err)

print(output.decode("utf-8"))

如果你好奇的话,这个问题还有很多关于这个话题的内容。

于 2018-02-27T22:22:11.573 回答