子进程 return 代码不同于 "echo $?"

Subprocess return code different than "echo $?"

我正在使用子进程调用 Python 中的 bash 命令,但我得到的 return 代码与 shell 显示的代码不同。

import subprocess
def check_code(cmd):
    print "received command '%s'" % (cmd)
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p.wait()
    print "p.returncode is '%d'" % (p.returncode)
    exit()
    if p.returncode == 0:
        return True
    else:
        return False
    #End if there was a return code at all
#End get_code()

发送时"ls /dev/dsk &> /dev/null",check_code returns 0,但"echo $?"在终端中产生“2”:

Welcome to Dana version 0.7
Now there is Dana AND ZOL

received command 'ls /dev/dsk &> /dev/null'
p.returncode is '0'
root@Ubuntu-14:~# ls /dev/dsk &> /dev/null
root@Ubuntu-14:~# echo $?
2
root@Ubuntu-14:~#

有人知道这里发生了什么吗?

您将其用作 subprocess.Popen(cmd, shell=True),将 cmd 用作字符串。

这意味着子进程将在后台调用 /bin/sh 并带有参数。因此,您将取回 shell.

的退出代码

如果您确实需要命令的退出代码,请将其拆分为列表并使用 shell=False

subprocess.Popen(['cmd', 'arg1'], shell=False)

根据 xi_ 的建议,我将命令拆分为 space 个划定的字段,但它未能 运行 使用“&>”和“/dev/null”。我删除了它们,它起作用了。

然后我将所有命令放回一起以在没有“&> /dev/null”的情况下对其进行测试,这也奏效了。似乎添加“&> /dev/null”会以某种方式抛出子进程。

Welcome to Dana version 0.7
Now there is Dana AND ZOL

received command 'cat /etc/fstab'
p.wait() is 0
p.returncode is '0'

received command 'cat /etc/fstabb'
p.wait() is 1
p.returncode is '1'

received command 'cat /etc/fstab &> /dev/null'
p.wait() is 0
p.returncode is '0'

received command 'cat /etc/fstabb &> /dev/null'
p.wait() is 0
p.returncode is '0'
root@Ubuntu-14:~# cat /etc/fstab &> /dev/null
root@Ubuntu-14:~# echo $?
0
root@Ubuntu-14:~# cat /etc/fstabb &> /dev/null
root@Ubuntu-14:~# echo $?
1
root@Ubuntu-14:~#

我最初在调用中添加了“&> /dev/null”,因为我在屏幕上看到了 STDERR 的输出。一旦我将 stderr=PIPE 添加到子进程调用中,它就消失了。我只是想默默地检查幕后输出的代码。

如果有人能解释为什么在 Python 中的子进程调用中添加“&> /dev/null”会导致它出现意外行为,我很乐意 select回答!

根据 subprocess.Popen,您的 Python 脚本中使用的 shell 是 sh。此 shell 是 POSIX 标准,与 Bash 相对,后者具有多个非标准功能,例如 shorthand 重定向 &> /dev/nullsh,Bourne shell,将此符号解释为 "run me in the background, and redirect stdout to /dev/null"。

由于您的 subprocess.Popen 打开了一个 sh,它在自己的后台运行 ls,因此使用 sh 的 return 值而不是 ls,在本例中为 0。

如果您希望 Python 具有 Bash 行为,我相信您可能需要重新配置(可能重新编译)Python 本身。只使用 sh 语法更简单,即 ls /dev/dsk 2> /dev/null.