【问题标题】:Issue with subprocess.check_call() returning 1 with netsh使用 netsh 返回 1 的 subprocess.check_call() 问题
【发布时间】:2015-11-27 22:00:18
【问题描述】:

我正在尝试使用 subprocess.check_call() 和 netsh 来更改我计算机的 NIC 卡设置。目前使用python 2.7和Windows7。

当我从 cmd.exe 运行时,这个命令是成功的:

netsh interface ip set address name="Local Area Connection" static 192.168.1.1 255.255.255.0 192.168.1.2

这个python脚本不成功:

import subprocess    
command = ['netsh','interface','ip','set','address','name="Local Area Connection"','static','192.168.1.1','255.255.255.0','192.168.1.2']
result = subprocess.check_call(command)

这是上面python脚本给出的回溯输出的最后一行:

CalledProcessError: Command '['netsh', 'interface', 'ip', 'set', 'address', 'name="Local Area Connection"', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.2']' returned non-zero exit status 1

所以,显然出了点问题,我正试图找出问题所在。我想解决的第一件事是返回码是什么意思?我希望我不是很密​​集,但https://python.readthedocs.org/en/v2.7.2/library/subprocess.html# 似乎并没有解释返回码的实际含义。我确实找到了这个线程,What is the return value of subprocess.call()?,但它通常只给出关于返回码的笼统陈述。有人知道如何找出特定于subprocess.check_call() 的返回码的含义吗?

这将帮助我开始进行故障排除,但如果有人对脚本失败的原因有任何想法,我将不胜感激。我尝试使用“以管理员身份运行”打开 cmd.exe,然后从那里运行 python 脚本,但结果是一样的。这个线程似乎是同一个问题,但我没有看到解决方案: Using subprocess.call() to pass commands to execute by cmd。我尝试设置command = netsh interface ip set address name="Local Area Connection" static 192.168.1.1 255.255.255.0 192.168.1.2subprocess.check_call(command,shell=True) 以及subprocess.check_call(shlex.split(command)),并且都返回代码'1'。

【问题讨论】:

    标签: python windows python-2.7 subprocess netsh


    【解决方案1】:

    返回码基本上是程序通知调用系统有关程序执行成功状态的一种非常简单的方法。一般来说,0 的返回码意味着一切正常。任何其他数字都被视为错误。现在,程序可以决定对不同的问题使用不同的返回码,然后提供一个注册表,哪个返回码意味着什么样的错误,但是这样做的应用程序并不多。更常见的是,特别是对于像 netsh 这样的面向人类的程序,只使用任何错误的返回码(通常是 1)然后在程序输出中显示错误消息。

    您应该使用catch_output 来捕获netsh 的输出,然后捕获异常并查看其中的错误消息:

    import subprocess    
    command = ['netsh', 'interface', 'ip', 'set', 'address', 'name="Local Area Connection"', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.2']
    
    try:
        result = subprocess.check_output(command)
    except subprocess.CalledProcessError as ex:
        print(ex.returncode, ex.output)
        raise
    

    这应该会在程序中止之前为您打印来自netsh 的输出,因此netsh 可能会告诉您出了什么问题。

    如果我不得不大胆猜测,我会说netsh 抱怨缺少管理员权限。为了更改网络接口的 IP 地址,您需要提升权限。因此,如果您的 Python 程序没有以管理员身份运行,那么您生成的子进程也不会以管理员身份运行。

    【讨论】:

    • 感谢您的回复。到目前为止,我已经意识到“错误处理”,但还没有真正使用它。需要从最佳实践开始,所以有理由这样做很好。不幸的是,在这种情况下,print(ex.returncode, ex.output) 给出的输出 (1, None)....... 并没有太大帮助。不是以管理员身份运行 cmd.exe 然后从那里执行 python 脚本来处理管理员的事情吗?我正在对此进行更多研究,因此我可以确信我是以管理员身份运行它。
    • 这很奇怪。它至少应该给你一些输出。你确定你把电话从check_call()改为check_output()吗?另外,至于您的实际问题,可能是name="Local Area Connection" 周围的引号。试试name=Local Area Connection
    • @poke,看来你的猜测是正确的。 subprocess.list2cmdline 将双引号转义为 "name=\"Local Area Connection\""。因此,netsh.exe 中的 CRT 启动代码在创建 argv 数组时不会删除它们。它们作为接口名称的一部分处理。
    • 为了确认这一点,我启动了(64 位)netsh.exe 进程挂起(即creationflags=CREATE_SUSPENDED);在netsh!wmain 上附加了一个带有断点的调试器,并恢复了主线程。我通过 ?? *((wchar_t **)@rdx + 5) 检查了 wmain 的参数 5,它计算为字符串 "name="Local Area Connection""。所以引号肯定会被解析为名称的一部分,至少在 C 运行时是这样。
    • @poke,你是对的,因为我忽略了你对subprocess.check_output() 的更改,并且去掉引号是错误的。 @eryksun,很高兴知道。我将花一些时间吸收您所说的内容,以及subprocess 模块的实际编写方式。 subprocess.list2cmdline 乍一看并不难。
    【解决方案2】:

    似乎您缺少在命令行中转义引号字符尝试使用:

    import subprocess    
    command = ['netsh','interface','ip','set','address','name=\\"Local Area Connection\\"','static','192.168.1.1','255.255.255.0','192.168.1.2']
    result = subprocess.check_call(command)
    

    【讨论】:

    • 感谢您的建议。我尝试了转义斜杠,但它给出了相同的结果(returncode=1)。另外,我认为通过对字符串使用单引号,我可以直接使用双引号而不使用转义斜杠吗?我之前也尝试过对字符串使用双引号,并且在这种情况下也肯定使用了转义斜杠。
    猜你喜欢
    • 2012-11-14
    • 2011-09-18
    • 2023-04-07
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多