子进程返回代码不同于“echo $?”

时间:2016-03-30 20:11:47

标签: python bash subprocess

我正在使用subprocess在Python中调用bash命令,而且我得到的返回代码与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返回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:~#

有谁知道这里发生了什么?

3 个答案:

答案 0 :(得分:3)

根据subprocess.Popen,您的Python脚本中使用的shell是sh。这个shell是POSIX标准,而不是Bash,它有几个非标准的功能,如速记重定向&> /dev/null。 {B} shell sh将此符号解释为"在后台运行我,并将stdout重定向到/ dev / null"。

由于您的subprocess.Popen在自己的背景中打开了sh ls,因此使用sh的返回值代替ls,这种情况是0。

如果你想用你的Python做Bash行为,我相信你可能不得不重新配置(可能重新编译)Python本身。使用sh ls /dev/dsk 2> /dev/null语法更简单。

答案 1 :(得分:0)

按照xi_的建议,我将命令分成空格描述的字段,但无法使用“&>”运行和“/ 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”会导致其意外行为,我很乐意选择它作为答案!

答案 2 :(得分:-1)

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

这意味着子进程将使用参数在引擎/bin/sh下调用。因此,您将获得shell的退出代码。

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

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