我有一个 shell 脚本和一个 python 脚本,组织如下(不能更改目录结构):
~
├── a.py
├── b
└── c.sh
MWE如下:
c.sh
#!/bin/sh
rcfile=$(mktemp)
export TEST1='hello'
cat <<-EOF > ${rcfile}
export TEST2='world'
EOF
${SHELL} --rcfile ${rcfile}
rm -f ${rcfile}
a.py
from subprocess import Popen, PIPE
p = Popen('./c.sh', cwd='./b', stdin=PIPE)
p.communicate(b'echo $TEST1\necho $TEST2\nexit')
当我执行 shell 脚本
c.sh
时,它会按预期显示两个变量。
但是,当从Python脚本
a.py
执行时,内部变量即TEST2
未设置。
我不能修改shell脚本。
有没有办法从Python脚本访问变量
TEST1
和TEST2
?
我尝试使用
pexpect
但仍然缺少第二个值 ($TEST2
)。我怀疑这是缓冲的问题。与此同时,我想出了一个解决办法:虽然你不能修改shell脚本;您可以修改它的副本。对于我的解决方案,我将制作一个副本,修改运行 shell 的行,以便它能够
代码:
#!/usr/bin/env python3
import pathlib
import subprocess
# Duplicate c.sh and modify the SHELL line
original_script = pathlib.Path("./b/c.sh")
modified_script = original_script.with_stem("c-copy")
content = original_script.read_text().splitlines()
with open(modified_script, "w", encoding="utf-8") as stream:
for line in content:
if line.startswith("${SHELL}"):
line = ". ${rcfile}\necho TEST1=$TEST1\necho TEST2=$TEST2"
stream.write(f"{line}\n")
# Run
modified_script.chmod(0o777)
process = subprocess.run(
["./b/c-copy.sh"],
text=True,
capture_output=True,
)
# Clean up
modified_script.unlink()
# Parse output and print. Assume that the shell script might produce
# other output, so we only grab lines with starts with "TEST"
shell_vars = dict(
line.split("=") for line in process.stdout.splitlines()
if line.startswith("TEST")
)
print(shell_vars)
输出:
{'TEST1': 'hello', 'TEST2': 'world'}
我在 Fedora 40 和 Python 3.12.4 中对此进行了测试。