上下文
我正在研究模拟集群。 为了尽可能地灵活(使用不同的模拟软件),我们创建了一个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
答案 0 :(得分:0)
您有几种选择:
部分或不支持bash的变量替换,例如实现一些python功能以重现bash的$VARIABLE
语法。
再现配置文件($VARIABLE
,${VARIABLE}
,${VARIABLE/x/y}
,$(cmd)
-所支持的bash的所有变量替换功能。
根据您对配置文件内容的信任程度,让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组成...使用正则表达式替换...只是看起来如此多行对我来说似乎是简单的请求