从python评估“带有shell变量的Shell命令行”,或者将python字符串作为shell命令行评估

时间:2019-11-28 19:40:03

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

上下文

我正在研究模拟集群。 为了尽可能地灵活(使用不同的模拟软件),我们创建了一个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严格将其解释为文本...这使命令行失败。严格来说,它是使用$ not变量的字符串,例如: 'fluent -3ddp -n$NUMPROCS -hosts=./hosts -file $JOBFILE'

我正在寻找的解决方案

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

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

2 个答案:

答案 0 :(得分:0)

您有几种选择:

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

  2. 再现配置文件($VARIABLE${VARIABLE}${VARIABLE/x/y}$(cmd)-所支持的bash的所有变量替换功能。

  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... && 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 <(...command...)使bash将该命令的输出视为文件并逐行运行其行。

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

表达式:我们希望对env之类的模式复制^FANCY=的输出。

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

编辑

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

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

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

答案 1 :(得分:0)

似乎我对这个问题的解释不够好,但是您的第三个解决方案似乎符合我的期望...尽管到目前为止,我还没有设法适应它

根据您的第三个解决方案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组成...使用正则表达式替换...只是看起来如此多行对我来说似乎是简单的请求