【问题标题】:Evaluate "Shell command line with shell variables" from python OR evaluate python string as shell command line从python评估“带有shell变量的Shell命令行”或将python字符串评估为shell命令行
【发布时间】:2023-04-09 18:51:01
【问题描述】:

上下文

我正在开发一个模拟集群。 为了尽可能灵活(使用不同的仿真软件),我们创建了一个 python 文件来解析定义环境变量的配置文件,以及启动仿真的命令行。该命令通过 SLURM sbatch 命令(shell $COMMAND)启动

问题

从 python 中,所有环境变量都注册到读取配置文件 我对使用其他环境变量(显示为 shell 变量)的变量 COMMAND 有疑问

例如

COMMAND = "fluent -3ddp -n$NUMPROCS -hosts=./hosts -file $JOBFILE"    
os.environ['COMMAND']=COMMAND    
NUMPROCS = "32"    
os.environ['NUMPROCS']=NUMPROCS    
[...]    
exe = Popen(['sbatch','template_document.sbatch'], stdout=PIPE, stderr=PIPE)

sbatch 将 COMMAND 分发到所有模拟节点,因为 COMMAND 是命令行

COMMAND 调用其他保存的环境。变量。 Shell 将其严格解释为文本......这使得命令行失败。它严格作为使用 $ 不变量的字符串,例如: 'fluent -3ddp -n$NUMPROCS -hosts=./hosts -file $JOBFILE'

我正在寻找的解决方案

我正在寻找一个简单的解决方案 解决方案 1:一个 1 到 3 个 python 命令行来评估 COMMAND 作为 shell 命令来回显 解决方案 2:将“字符串”$COMMAND 中的变量评估为变量的 Shell 命令 最后从 sbatch 中启动的命令应该是

fluent -3ddp -n32 -hosts=./hosts -file /path/to/JOBFILE

【问题讨论】:

    标签: python bash environment-variables pass-by-reference slurm


    【解决方案1】:

    你有几个选择:

    1. 部分或不支持 bash 的变量替换,例如实现一些 python 功能来重现 bash 的 $VARIABLE 语法。

    2. 重现配置文件中支持的所有 bash 变量替换工具($VARIABLE${VARIABLE}${VARIABLE/x/y}$(cmd) - 随便什么。

    3. 让 bash 完成繁重的工作,以牺牲性能和可能的安全性,这取决于您对配置文件内容的信任。

    我将在这里展示第三个,因为它是最具弹性的(同样,尽管存在安全问题)。假设你有这个配置文件,config.py:

    REGULAR   =   "some-text"
    EQUALS = "hello = goodbye" # trap #1: search of '='
    SUBST = "decorated $REGULAR"
    FANCY   = "xoxo${REGULAR}xoxo"
    CMDOUT = "$(date)"
    BASH_A = "trap" # trap #2: avoid matching variables like BASH_ARGV
    QUOTES = "'\"" # trap #3: quoting
    

    那么你的python程序就可以运行下面的咒语了:

    bash -c 'source <(sed "s/^/export /" config.py | sed "s/[[:space:]]*=[[:space:]]*/=/") && env | grep -f <(cut -d= -f1 config.py | grep -E -o "\w+" | sed "s/.*/^&=/")'
    

    这将产生以下输出:

    SUBST=decorated some-text
    CMDOUT=Thu Nov 28 12:18:50 PST 2019
    REGULAR=some-text
    QUOTES='"
    FANCY=xoxosome-textxoxo
    EQUALS=hello = goodbye
    BASH_A=trap
    

    然后您可以使用 python 阅读,但请注意引号现在已消失,因此您必须考虑到这一点。

    咒语解释:

    bash -c 'source ...instructions... &amp;&amp; env | grep ...expressions...' 告诉 bash 读取和解释指令,然后 grep 表达式的环境。我们将把配置文件变成修改 bash 环境的指令。

    如果您尝试使用set 而不是env,则输出与引用不一致。使用 env 可以避免陷阱 #3。

    说明:我们将为表单创建说明:

    export FANCY="xoxo${REGULAR}xoxo"
    

    以便 bash 可以解释它们并且 env 可以读取它们。

    • sed "s/^/export /" config.py 为变量添加前缀export
    • sed "s/[[:space:]]*=[[:space:]]*/=/" 将赋值格式转换为 bash 可以使用 source 读取的语法。使用 s/x/y/ 而不是 s/x/y/g 可以避免陷阱 #1。
    • source &lt;(...command...) 使 bash 将命令的输出视为文件并逐行运行。

    当然,避免这种复杂性的一种方法是让文件开始使用 bash 语法。如果是这种情况,我们将使用source config.sh 而不是source &lt;(...command...)

    表达式:我们想对env 的输出进行grep,以获取^FANCY= 等模式。

    • cut -d= -f1 config.py | grep -E -o "\w+"config.py 中查找变量名。
    • sed "s/.*/^&amp;=/" 将变量名称(如 FANCY)转换为 grep 搜索表达式,如 ^FANCY=。这是为了避免陷阱 #2。
    • grep -f &lt;(...command...) 获取 grep 将命令的输出视为每行包含一个搜索表达式的文件,在本例中为 ^FANCY=^CMDOUT= 等。

    编辑

    由于您实际上只想将此环境传递给另一个 bash 命令而不是在 python 中使用它,因此您实际上可以让 python 运行它:

    bash -c 'source <(sed "s/^/export /" config.py | sed "s/[[:space:]]*=[[:space:]]*/=/") && $COMMAND'
    

    (假设在配置文件中指定了COMMAND)。

    【讨论】:

    • 你好@Root 非常感谢你如此详细和快速的回​​答。
    • 非常感谢:这正是我的需要 - 将测试并让您知道
    【解决方案2】:

    似乎我对这个问题的解释不够清楚,但你的第三个解决方案似乎符合我的期望......虽然到目前为止我还没有设法适应它

    基于您的第 3 个解决方案 BASH,我将使其更直接: 假设我在运行python后得到了关注,并且无法修改

    EXPORT COMMAND='fluent -3ddp -n$NUMPROCS -hosts=./hosts -file $JOBFILE'
    EXPORT JOBFILE='/path/to/jobfile'
    EXPORT NUMPROCS='32'
    EXPORT WHATSOEVER='SPECIFIC VARIABLE TO SIMULATION SOFTWARE'
    

    我希望使用 $COMMAND / $JOBFILE /$NUMPROCS 从 slurm 批处理文件 (bash) 中执行以下操作

    fluent -3ddp -n32-hosts=./hosts -file /path/to/jobfile
    

    请注意:我在 python 中有备份解决方案 - 我设法用它的值替换 $VARIABLE - 基于假设 $VARIABLE 不是由另一个 $variable 组成...使用正则表达式替换...只是看起来很多有什么对我来说似乎很简单的要求

    【讨论】:

      最近更新 更多