我在 Win 10 下使用 Msys2 可移植,但我想这同样适用于许多其他 Linux/bashe。
当从 shell 提示符运行时,我如何让 python 脚本了解其 shell 函数和相应的参数?
我有一个 bash shell,其中我定义了一个 shell 函数myfun
$ type myfun
myfun is a function
myfun ()
{
...
(this contains a call to a shell script,
that is found in a directory which is part of $PATH)
}
可以采用参数,例如$ myfun d
, 我有一个 python 脚本myscript.py
从 bash shell 运行时运行良好。 现在我想向myscript.py
添加行以从其中执行myfun
,并使其也与(与以前相同)一起工作
$ python3 myscript.py
编辑#1: 收到答案后,我导出了带有
export -f myfun
的函数。 然后我在脚本中尝试了 6 种替代方案:(使用/不使用bash -c
),结合 (subprocess.run
、os.system
、os.popen
)。
我在这里列出了 6 种组合中的每一个,添加到myscript.py
的行,以及执行python3 myscript.py
时获得的输出:
- 添加
import subprocess
subprocess.run(["myfun", "d"])
获得(与以前相同)
Traceback (most recent call last):
...
FileNotFoundError: [Errno 2] No such file or directory: 'myfun'
- >已添加
import os
os.system("myfun d")
获得了预期的结果。
- >已添加
import os
stream = os.popen("myfun d")
获得 没有错误,但显然什么都不做(很奇怪,必须进一步检查发生了什么)。
- >已添加
import subprocess
subprocess.run(["bash", "-c", "myfun", "d"])
获得: 执行了函数,但忽略了函数参数。
- >已添加
import os
os.system("bash -c "myfun d"")
获得了预期的结果。
- 已添加
import os
stream = os.popen("bash -c "myfun d"")
获得 没有错误,但显然什么都不做(很奇怪,必须进一步检查发生了什么)。
原始问题和状态:
我尝试了一些选项,但都失败了(请参阅下面的详细信息)。 一方面,似乎即使从 bash shell 执行myscript.py
,它也会在不知道我的 shell 函数的情况下启动一个单独的sh
shell。 另一方面,如果将print( os.environ )
添加到myscript.py
,我看到在~/.bashrc
中设置的环境变量,因此至少脚本从 shell 正确继承了它。
我在这里列出了添加到
myscript.py
的行,以及执行python3 myscript.py
时获得的输出:
- 添加
import subprocess
subprocess.run(["myfun", "d"])
获得
Traceback (most recent call last):
...
FileNotFoundError: [Errno 2] No such file or directory: 'myfun'
- >已添加
import os
os.system("myfun d")
获得
sh: myfun: command not found
- >已添加
import os
stream = os.popen("myfun d")
获得
/bin/sh: myfun: command not found
默认情况下,环境是私有的。导出函数并确保在系统调用中运行bash
。myfun
是一个bash函数,你必须运行bash
才能运行它的函数。
$ myfun() { echo 1; }
$ export -f myfun
$ python <<<'import os; os.system("bash -c myfun")'
1
$ python <<<'import subprocess as s; s.run(["bash", "-c", "myfun"])'
1
$ python <<<'import os; os.popen("bash -c 'myfun"); # ... '
我通常将参数传递给内部 bash 命令作为脚本的参数,并在扩展$@
传递正确引用:
$ myfun() { echo "$#=$#" "$*=$*"; }
$ export -f myfun
$ python <<<'import os; os.system("bash -c "myfun \"$@\"" -- d")'
$#=1 $*=d
# or way better use subprocess
$ python <<<'import subprocess as s; s.run(["bash", "-c", "myfun "$@"", "--", "d"])'
$#=1 $*=d
# but still can do the more unsafe version
# that will undergo word expansion or you have to properly escape the strings
# (and double-double escape for `os.systems`)
$ python <<<'import subprocess as s; s.run(["bash", "-c", "myfun d"])'
$#=1 $*=d