为什么 Popen.communicate() return 在“||”之后没有输出操作员?

Why doesn't Popen.communicate() return the output after the "||" operator?

import subprocess

cmd = "source ~/.bash_profile || echo hello"
proc = subprocess.Popen(cmd,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        shell=True)
(out, err) = proc.communicate()
code = proc.returncode
print(f"code:{code}, out:{out}, err:{err}")

输出:

code:1, out:b'', err:b'/bin/sh: /Users/xxx/.bash_profile: No such file or directory\n'

我没有bash_profile,但为什么out不包含"hello"

bashsh 之间可能存在差异 您可以在没有 python 的情况下复制它。这也是有道理的 python 默认情况下依赖于 /bin/sh,所以它公开了行为

#!/bin/sh
. abc || echo hello 
 # output: ./test.sh: line 3: .: abc: file not found

#!/bin/bash    
. abc || echo hello
# output: ./test.sh: line 3: abc: No such file or directory
# hello

可能通过 executable 参数将默认设置更改为 /bin/bash 可以以某种方式纠正它

cmd = "source ~/.bash_profile || echo hello"
proc = subprocess.Popen(cmd,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        shell=True,
                        executable="/bin/bash")

此行为似乎未记录在 bash 手册页中,但开放标准指出:If no readable file is found, a non-interactive shell shall abort; an interactive shell shall write a diagnostic message to standard error, but this condition shall not be considered a syntax error. (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_18_01) 当 运行 非交互式从 python 开始,shell 只是中止而不是 运行 ||

之后的代码