对来自python操作系统和命令行的引用的不同解释



我正在运行一个python3脚本,它在Debian 9上执行以下代码片段:

os.environ["PA_DIR"] = "/home/myname/some_folder"
command_template = ("sudo java -Dconfig.file=$PA_DIR/google.conf "
"-jar ~/big/cromwell-42.jar run $PA_DIR/WholeGenomeGermlineSingleSample.wdl "
"-i {} -o $PA_DIR/au_options.json > FDP{}.log 2>&1")
command = command_template.format("test.json, "1")
os.system("screen -dm -S S{} bash -c '{}'".format("1", command))

PA_DIR的使用按预期工作。当我在命令行上尝试时:

PA_DIR="/home/myname/some_folder"    
screen -dm -S S1 bash -c 'sudo java -Dconfig.file=$PA_DIR/google.conf -jar ~/big/cromwell-42.jar run $PA_DIR/WholeGenomeGermlineSingleSample.wdl -i test.json -o $PA_DIR/au_options.json > FDP1.log 2>&1'

由于单引号,它不进行变量替换,我不得不用双引号替换它们(它抱怨找不到文件/google.conf)。 当python运行它时有什么不同? 谢谢!

Pythonos.system()调用 C 库的底层system函数,在 POSIX 系统上相当于执行类似

sh -c "your_command and all its arguments"

因此,命令和所有参数都已经被双引号括起来,这会进行环境变量替换。字符串内的任何单引号都与变量替换无关。


您可以轻松测试它。在外壳中做类似的事情

$ foo="bar"
$ echo "foo is '$foo'"    # Will print foo is 'bar'
$ echo 'foo is "$foo"'    # Will print foo is "$foo"

等待您对 daltonfury42 的回答,我敢打赌问题是,在命令行中运行时,您没有导出 PA_DIR 环境变量,因此它不会出现在第二个 bash 解释器中。由于米希尔的回答,它的行为有所不同。

如果您运行

PA_DIR=foo

您只声明了一个 bash 变量,但它不是环境变量。然后

bash -c "echo $PA_DIR"

这将输出 Foo,因为您当前的解释器插入$PA_DIR,然后使用命令echo foo引发第二个 bash 进程。但

bash -c 'echo $PA_DIR'

这可以防止您的 bash 解释器插入它,因此它会使用 comandecho $PA_DIR引发第二个 bash 进程。但在第二个过程中,变量PA_DIR不存在。

如果您开始跑步之旅

export PA_DIR=foo

这将成为子进程可以访问的环境变量,因此

bash -c 'echo $PA_DIR'

将输出 Foo,因为嵌套的 bash 解释器可以访问该变量,即使父 bash 解释器没有插值它。

任何类型的子过程也是如此。尝试跑步

PA_DIR=foo
python3 -c 'import os; print(os.environ.get("PA_DIR"))'
python3 -c "import os; print(os.environ.get('PA_DIR'))"
export PA_DIR=foo
python3 -c 'import os; print(os.environ.get("PA_DIR"))'
python3 -c "import os; print(os.environ.get('PA_DIR'))"

在你的壳里。这里不涉及报价!

当您在 Python 脚本中使用os.environ字典时,Python 将为您导出变量。这就是为什么你会看到变量由以下任一

os.system("bash -c 'echo $PA_DIR'")

os.system('bash -c "echo $PA_DIR"')

但请注意,在每种情况下,插入变量的要么是父进程,要么是子 shell 进程。

您必须在此处了解您的流程树:

/bin/bash  # but it could be a zsh, fish, sh, ...
|- /usr/bin/python3  # presumably
|- /bin/sh  # because os.system uses that
|- /bin/bash

如果希望环境变量存在于嵌套最多的进程中,则必须将其导出到上部树中的任何位置。或者就在这个过程中。

最新更新