【问题标题】:Manage shell command result from Python script管理 Python 脚本的 shell 命令结果
【发布时间】:2016-08-10 05:55:46
【问题描述】:

python 脚本运行这个命令:

return_code = call("iw wlan0 scan | sed -e 's#(on wlan# (on wlan#g' | awk -f scan.awk > scan.txt", shell=True)

我只想在命令运行良好的情况下继续我的代码。但即使命令失败,return_code 也始终为“0”。

更准确地说,失败表示为

command failed: Device or resource busy (-16)

如何“捕获”此消息并避免程序继续运行?如果出现“命令失败”错误,我想重复 shell 命令,但我不知道该怎么做。

【问题讨论】:

  • Check_call() 和 check_output() 不能解决我的问题。命令本身的执行总是成功的,因此返回码是“0”。问题是“iw wlan0 scan”可以返回命令失败消息,这对我的脚本来说是个问题,因为它认为一切顺利,但实际上没有
  • 使用check_output可以查看错误信息中是否包含失败信息
  • 尝试直接在 shell 上检查你的命令,比如:iw wlan0 scan | sed -e 's#(on wlan# (on wlan#g' | awk -f scan.awk > scan.txt; echo $?
  • 问题是 bash 不会跨管道传播错误。有一个使用命名管道的部分解决方案:return_code = call('mkfifo pipe && iw wlan0 scan > pipe', shell=True) 问题是这会阻塞,直到您从管道读取,这意味着您需要线程。这意味着您需要跨线程边界传递线程调用的状态。我把它作为练习留给别人。

标签: python shell error-handling subprocess


【解决方案1】:

你可以这样做:

import subprocess

cmd = "iw wlan0 scan | sed -e 's#(on wlan# (on wlan#g' | awk -f scan.awk > scan.txt"
cmd_err = "command failed: Device or resource busy"
output = cmd_err

while cmd_err in output:
    # maybe add a delay and a "max no. of retries" counter
    output = subprocess.check_output(cmd, shell=True)

# success - rest of your code

我不能写shell=True 而不提及使用它会带来某些安全风险(代码/命令注入)。尽可能避免使用它,并且永远不要将它用于不受信任的输入。

【讨论】:

    【解决方案2】:

    这取决于您希望得到命令的哪一部分。你应该得到的是(我认为——现在我自己正在学习这些东西)“awk -f scan.awk > scan.txt”的返回码。

    我怀疑您真正想要的是将是否继续使用 sed/awk 组件基于“iw wlan0 扫描”的结果,因此将其分为 2 个部分进行扫描,检查结果,如果返回码为 0/输出不是“命令失败:设备或资源忙”。

    我很想提供一个语法和程序上完美的例子来说明如何做到这一点,但我也只是在学习:)

    【讨论】: