kra*_*r65 55 python bash subprocess
我正在尝试从Python中进行比特币支付.在bash中我通常会这样做:
bitcoin sendtoaddress <bitcoin address> <amount>
Run Code Online (Sandbox Code Playgroud)
例如:
bitcoin sendtoaddress 1HoCUcbK9RbVnuaGQwiyaJGGAG6xrTPC9y 1.4214
Run Code Online (Sandbox Code Playgroud)
如果它是成功的我得到一个事务ID作为输出,但如果我尝试转移大于我的比特币余额的数量,我得到以下输出:
error: {"code":-4,"message":"Insufficient funds"}
Run Code Online (Sandbox Code Playgroud)
在我的Python程序中,我现在尝试按以下方式进行付款:
import subprocess
try:
output = subprocess.check_output(['bitcoin', 'sendtoaddress', address, str(amount)])
except:
print "Unexpected error:", sys.exc_info()
Run Code Online (Sandbox Code Playgroud)
如果有足够的余额它可以正常工作,但如果没有足够的余额sys.exc_info()打印出来:
(<class 'subprocess.CalledProcessError'>, CalledProcessError(), <traceback object at 0x7f339599ac68>)
Run Code Online (Sandbox Code Playgroud)
它不包括我在命令行上得到的错误.所以我的问题是; 如何{"code":-4,"message":"Insufficient funds"}从Python中获取输出的错误()?
欢迎所有提示!
Fer*_*yer 84
根据subprocess.check_output()文档,错误引发的异常有一个output属性,您可以使用该属性来访问错误详细信息:
try:
subprocess.check_output(...)
except subprocess.CalledProcessError as e:
print e.output
Run Code Online (Sandbox Code Playgroud)
然后,您应该能够分析此字符串并使用json模块解析错误详细信息:
if e.output.startswith('error: {'):
error = json.loads(e.output[7:]) # Skip "error: "
print error['code']
print error['message']
Run Code Online (Sandbox Code Playgroud)
Phi*_*l R 27
我不认为接受的解决方案处理在stderr上报告错误文本的情况.从我的测试中,异常的输出属性不包含stderr的结果,并且docs警告不要在check_output()中使用stderr = PIPE.相反,我建议通过添加stderr支持对JF Sebastian的解决方案进行一些小的改进.毕竟,我们试图处理错误,stderr经常被报告.
from subprocess import Popen, PIPE
p = Popen(['bitcoin', 'sendtoaddress', ..], stdout=PIPE, stderr=PIPE)
output, error = p.communicate()
if p.returncode != 0:
print("bitcoin failed %d %s %s" % (p.returncode, output, error))
Run Code Online (Sandbox Code Playgroud)
Juu*_*nen 11
从Python 3.5开始,subprocess.run()支持check参数:
如果check为 true,并且进程以非零退出代码退出,则会引发 CalledProcessError 异常。该异常的属性包含参数、退出代码以及 stdout 和 stderr(如果捕获了它们)。
一个将引发并打印出的简单示例CalledProcessError:
import subprocess
try:
subprocess.run("exit 1", shell=True, check=True, timeout=15, capture_output=True)
except subprocess.CalledProcessError as e:
print(e) # Output: Command 'exit 1' returned non-zero exit status 1.
Run Code Online (Sandbox Code Playgroud)
试图"转移大于比特币余额的金额"并不是意外错误.您可以Popen.communicate()直接使用而不是check_output()避免不必要地引发异常:
from subprocess import Popen, PIPE
p = Popen(['bitcoin', 'sendtoaddress', ..], stdout=PIPE)
output = p.communicate()[0]
if p.returncode != 0:
print("bitcoin failed %d %s" % (p.returncode, output))
Run Code Online (Sandbox Code Playgroud)
这对我来说很有效。它捕获子进程的 stdout 和 stderr 输出(对于 python 3.8):
from subprocess import check_output, STDOUT
cmd = "Your Command goes here"
try:
cmd_stdout = check_output(cmd, stderr=STDOUT, shell=True).decode()
except Exception as e:
print(e.output.decode()) # print out the stdout messages up to the exception
print(e) # To print out the exception message
Run Code Online (Sandbox Code Playgroud)
正如@Sebastian 所提到的,默认解决方案应该旨在使用run():https :
//docs.python.org/3/library/subprocess.html#subprocess.run
这是一个方便的实现(随意使用打印语句或您正在使用的其他日志记录功能更改日志类):
import subprocess
def _run_command(command):
log.debug("Command: {}".format(command))
result = subprocess.run(command, shell=True, capture_output=True)
if result.stderr:
raise subprocess.CalledProcessError(
returncode = result.returncode,
cmd = result.args,
stderr = result.stderr
)
if result.stdout:
log.debug("Command Result: {}".format(result.stdout.decode('utf-8')))
return result
Run Code Online (Sandbox Code Playgroud)
和示例用法(代码不相关,但我认为它可以作为示例,说明使用这个简单的实现是多么易读和易于处理错误):
try:
# Unlock PIN Card
_run_command(
"sudo qmicli --device=/dev/cdc-wdm0 -p --uim-verify-pin=PIN1,{}"
.format(pin)
)
except subprocess.CalledProcessError as error:
if "couldn't verify PIN" in error.stderr.decode("utf-8"):
log.error(
"SIM card could not be unlocked. "
"Either the PIN is wrong or the card is not properly connected. "
"Resetting module..."
)
_reset_4g_hat()
return
Run Code Online (Sandbox Code Playgroud)
这里有很好的答案,但在这些答案中,没有一个答案与堆栈跟踪输出中的文本一起出现,这是异常的默认行为。
如果您希望使用格式化的回溯信息,您可能希望:
import traceback
try:
check_call( args )
except CalledProcessError:
tb = traceback.format_exc()
tb = tb.replace(passwd, "******")
print(tb)
exit(1)
Run Code Online (Sandbox Code Playgroud)
正如您可能知道的那样,如果您希望阻止显示 check_call( args ) 中有密码,则上述内容很有用。