为何用subprocess.Popen调用bash脚本时source方式无法执行?
为什么用subprocess.Popen调用bash脚本时,直接执行正常但source/.调用失败?
先看测试代码和执行输出:
测试文件代码
test_python.py
import sys import os import subprocess os.putenv("testvar", "testvalue") test = subprocess.Popen("./test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() print(test) test = subprocess.Popen(". test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() print(test) test = subprocess.Popen("source test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() print(test) test = subprocess.Popen("/bin/bash test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() print(test) test = subprocess.Popen("/bin/sh test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() print(test)
test_shell.sh
#!/bin/bash echo "$testvar"
执行输出
('testvalue\n', '') ('', '/bin/sh: .: test_shell.sh: cannot open [No such file or directory]\n') ('', '/bin/sh: .: test_shell.sh: cannot open [No such file or directory]\n') ('testvalue\n', '') ('testvalue\n', '')
原因分析
- 默认shell的差异:当
subprocess.Popen设置shell=True时,默认调用系统的/bin/sh(多数Linux发行版中sh是dash的软链接),而非脚本指定的bash。source是bash专属内置命令,sh不识别,会自动 fallback 到.命令,但核心问题不在命令本身。 - 脚本查找规则不同:
- 直接执行
./test_shell.sh或用/bin/bash test_shell.sh时,要么明确指定了当前目录的相对路径(./),要么bash作为解释器会优先在当前工作目录查找未带路径的脚本,所以能找到文件。 - 用
.命令调用test_shell.sh时,sh会严格按照$PATH环境变量定义的目录查找脚本,当前工作目录默认不在$PATH中,因此提示找不到文件。
- 直接执行
解决方法
方法一:指定脚本的相对路径
在.或source命令里给脚本加上./前缀,明确告知shell脚本在当前目录:
test = subprocess.Popen(". ./test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() test = subprocess.Popen("source ./test_shell.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
方法二:强制使用bash作为执行shell
给subprocess.Popen添加executable="/bin/bash"参数,强制用bash执行命令,这样既能正常识别source命令,bash的.命令也会优先在当前目录查找脚本:
test = subprocess.Popen("source test_shell.sh", shell=True, executable="/bin/bash", stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() test = subprocess.Popen(". test_shell.sh", shell=True, executable="/bin/bash", stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
内容的提问来源于stack exchange,提问作者silence_of_the_lambdas
相关产品推荐
相关产品推荐

