为啥这个来自 python 的 bash 调用不起作用?

Posted

技术标签:

【中文标题】为啥这个来自 python 的 bash 调用不起作用?【英文标题】:Why does this bash call from python not work?为什么这个来自 python 的 bash 调用不起作用? 【发布时间】:2014-08-12 00:21:21 【问题描述】:

我有点玩弄比特币。当我想获取有关本地比特币安装的一些信息时,我只需运行 bitcoin getinfo 就会得到如下信息:


    "version" : 90100,
    "protocolversion" : 70002,
    "walletversion" : 60000,
    "balance" : 0.00767000,
    "blocks" : 306984,
    "timeoffset" : 0,
    "connections" : 61,
    "proxy" : "",
    "difficulty" : 13462580114.52533913,
    "testnet" : false,
    "keypoololdest" : 1394108331,
    "keypoolsize" : 101,
    "paytxfee" : 0.00000000,
    "errors" : ""

我现在想在 Python 中执行此调用(在有人指出之前;我知道有 Python implementations for Bitcoin,我只是想自己学习这样做)。所以我首先尝试执行一个简单的ls 命令,如下所示:

import subprocess
process = subprocess.Popen('ls', stdout=subprocess.PIPE)
output = process.communicate()[0]
print output

这工作正常,按预期打印出文件和文件夹列表。于是我就这样做了:

import subprocess
process = subprocess.Popen('bitcoin getinfo', stdout=subprocess.PIPE)
output = process.communicate()[0]
print output

但这会产生以下错误:

Traceback (most recent call last):
  File "testCommandLineCommands.py", line 2, in <module>
    process = subprocess.Popen('bitcoin getinfo', stdout=subprocess.PIPE)
  File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

在这里我有点迷路了。有人知道这里有什么问题吗?欢迎所有提示!

[编辑] 使用下面的优秀答案,我现在制作了以下功能,这对其他人也可能派上用场。它接受一个字符串,或者一个带有单独参数的可迭代对象,如果它是 json 则解析输出:

def doCommandLineCommand(command):
    process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=isinstance(command, str))
    output = process.communicate()[0]
    try:
        return json.loads(output)
    except ValueError:
        return output

【问题讨论】:

你确定你的脚本真的能看到“比特币”可执行文件吗?如果它位于 /usr/bin 或同等位置,请尝试提供完整路径。 ls 是一个 shell 命令,可以在任何地方访问,这就是它起作用的原因。 我猜你现在可以使用subprocess.check_output了!请注意potential security problems with shell=True 【参考方案1】:

在参数中使用序列:

process = subprocess.Popen(['bitcoin', 'getinfo'], stdout=subprocess.PIPE)

或将shell参数设置为True

process = subprocess.Popen('bitcoin getinfo', stdout=subprocess.PIPE, shell=True)

您可以在documentation找到更多信息:

args 是所有调用所必需的,它应该是一个字符串,或一系列程序参数。提供一系列参数通常是首选,因为它允许模块处理任何所需的参数转义和引用(例如,允许文件名中的空格)。如果传递单个字符串,shell 必须为 True(见下文),否则字符串必须简单地命名要执行的程序而不指定任何参数。

【讨论】:

你给的第一个选项仍然给我一个错误说File "/usr/lib/python2.7/subprocess.py", line 659, in __init__ raise TypeError("bufsize must be an integer"),但第二个选项确实有效!惊人的!知道为什么我会收到第一个选项的错误吗? @kramer65 你确定你使用['bitcoin', 'getinfo'] 而不是'bitcoin', 'getinfo'?括号是必需的。【参考方案2】:

使用以下代码:

process = subprocess.Popen(['bitcoin', 'getinfo'], stdout=subprocess.PIPE)

你不能使用空格来传递参数。

【讨论】:

感谢您的建议。我试过了,但我收到一个错误消息:File "/usr/lib/python2.7/subprocess.py", line 659, in __init__ raise TypeError("bufsize must be an integer")。知道为什么这也会失败吗? @kramer65 我想你忘记了[] 传递了args 绝对正确!谢谢!

以上是关于为啥这个来自 python 的 bash 调用不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我必须 sudo 来自守护进程的命令?

为啥我的 Linux bash 中这个简单的 FOR LOOP 不起作用?

有没有办法运行来自 bash 的 zip 文件中的 python 脚本?

为啥来自其他用户的 Digest 身份验证 Java HttpClient 代码对我不起作用? [复制]

为啥我的适配器更新不起作用

Pybind11:为啥来自 Python 的异步调用不能在 C++ 中正确执行回调?