Bash命令在终端中有效,但在python脚本中的“子进程”中无效[重复]

Posted

技术标签:

【中文标题】Bash命令在终端中有效,但在python脚本中的“子进程”中无效[重复]【英文标题】:Bash command works in terminal, but not within 'subprocess' in a python script [duplicate] 【发布时间】:2021-02-20 14:52:32 【问题描述】:

我正在尝试使用一些粒子物理软件并在循环中运行它,每次都会稍微改变变量。它具有获取 txt 文件并为此扫描相关命令的特定功能,因此我自然会尝试使用它。我写了一个 python 脚本(最初是用 python3 编写的,可以在我的笔记本电脑上运行,但我需要转移到大学的集群。我已经转换为 python2,因为粒子物理软件本身是 python 2 并试图同时运行两者同时在集群上安装python版本不是我知道该怎么做的事情。特别是集群安装了python2.6.9,我没有任何能力改变它,我也无法更新它或安装新模块。我的问题部分代码是:

     def run_madgraph():
        # starts madgraph and tells it to run mg5_aMC using mg_run_iridis.txt as a file for it.
            print('starting....')
            subprocess.check_call(['python', './madgraph/bin/mg5_aMC mg_run_iridis.txt'])

mg5_aMC 启动物理软件,mg_run_iridis.txt 是包含变量信息的文本文件。我不明白为什么这不起作用,因为以下命令在 bash 终端(在集群上)中运行良好:

    python ./madgraph/bin/mg5_aMC mg_run_iridis.txt

据我所知,问题出在 python-bash 方面,而不是物理软件中的任何内容。我得到的错误是:

(MGenv) [cb27g11@green0155 Development]$ python MainIridis_script.py 
about to run madgraph 1.0 0.9
starting....
python: can't open file '/home/cb27g11/Development/./madgraph/bin/mg5_aMC mg_run_iridis.txt': [Errno 2] No such file or directory
Traceback (most recent call last):
  File "/home/cb27g11/Development/MainIridis_script.py", line 41, in <module>
    the_main_event()
  File "/home/cb27g11/Development/MainIridis_script.py", line 21, in the_main_event
    run_madgraph()
  File "/home/cb27g11/Development/MainIridis_script.py", line 38, in run_madgraph
    subprocess.check_call(['python', './madgraph/bin/mg5_aMC mg_run_iridis.txt'])
  File "/home/cb27g11/.conda/envs/MGenv/lib/python3.9/subprocess.py", line 373, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['python', './madgraph/bin/mg5_aMC mg_run_iridis.txt']' returned non-zero exit status 2.

明确一点,/home/cb27g11/Development,绝对存在:

(MGenv) [cb27g11@green0155 Development]$ pwd
/home/cb27g11/Development

所涉及的各种文件也是如此:

(MGenv) [cb27g11@green0155 Development]$ ls
AD_noCharge_021020.tar.gz  NoChar_Allh_1.0_0.9  mg_run_basic.txt
MainIridis_script.py       NoChar_Allh_1_0.9    mg_run_iridis.txt
NoCh_h1Only.tar.gz         iridis_script.pbs    py.py
NoCh_h2Only.tar.gz         madgraph

包括mg5_aMC:

(MGenv) [cb27g11@green0155 Development]$ cd madgraph/
(MGenv) [cb27g11@green0155 madgraph]$ cd bin
(MGenv) [cb27g11@green0155 bin]$ ls
mg5  mg5_aMC  py.py

我不知道该怎么做,最终不管我怎么做,我仍然需要在另一个脚本(这次是 bash)中调用这个脚本文件才能将它提交到集群。

我不确定是否可以完全避免使用 python 脚本并切换到 bash,我怀疑至少其中一些需要保留在 python 中,但我是物理学家而不是程序员,所以我很容易出错!无论如何,这是完整的脚本:

from __future__ import absolute_import, division, print_function
    import numpy as np
    import subprocess
    import fileinput
    
    tan_beta = np.arange(1, 21.2, 0.2) #Array of tan(beta) values
    sin_bma = np.arange(0.9, 1.001, 0.001)#Array of sin(beta-alpha) values
    hcm =  1.500000e+05 # Mass of charged Higgses in GeV
    textfilepath = 'mg_run_iridis.txt' #path to txt file madgraph will use
    Process = 'NoChar_Allh'
    
    def the_main_event():
            with open('mg_run_basic.txt','r') as old_card:
                    text =old_card.read() #stores string of old_card ready for editing
            for i in range(0, len(tan_beta)):
                    tb = tan_beta[i] # loops over tan(beta) values
                    for j in range(0, len(sin_bma)):
                            sbma = sin_bma[j] # loops over sin(beta-alpha) values
                            make_input(tb, sbma, hcm, text)
                            print('about to run madgraph ' + str(tb) + ' ' + str(sbma))
                            run_madgraph()
    
    def make_input(Tb, Sbma, Hcm, Text):
    # inputs are the value of tan_beta, the value of sin(beta-alpha) values, the desired mass for the charged higgses and a string of text
    
            with open(textfilepath, 'w') as new_card:
            #simulation card, the .txt file that gets fed to madgraph
                    sim_card = Text.replace('TBV', str(Tb))
                    sim_card = sim_card.replace('SBMAV', str(Sbma))
                    sim_card = sim_card.replace('HCMV', str(Hcm))
                    sim_card = sim_card.replace('NAME', str(Process)+'_' + str(Tb) +'_' + str(Sbma))
                    new_card.write(sim_card) # saves new txt file for madgraph
    
    
    def run_madgraph():
    # starts madgraph and tells it to run mg5_aMC using mg_run_iridis.txt as a file for it.
            print('starting....')
            subprocess.check_call(['python', './madgraph/bin/mg5_aMC mg_run_iridis.txt'])
    
    
    the_main_event()

从错误来看,它似乎将 madgraph 可执行文件(我不确定这是否是正确的术语,我的意思是启动 propgram 的文件)作为模块处理?

任何帮助将不胜感激!

【问题讨论】:

我猜米哈伊尔写的是对的。只是一个补充。如果您遇到类似 blablabla “不可调用”之类的错误,那么您应该检查您放置了一些 () 的对象类型,因为这告诉 python 将对象解释为可调用对象,如果对象没有实现 @987654329,python 会抱怨@。在上述情况下,您可以执行 help(subprocess) 来查看它是什么类型的对象。 顺便说一句,当你的字符串没有shell指令时,你为什么要使用shell=Truesubprocess.run(['python', './madgraph/bin/mg5_aMC', 'mg_run_iridis.txt']) 效率稍高一些,并且更容易修改参数化值而不会引入安全错误(查找“shell 注入”)。 但最好不要将 Python 作为 Python 的子进程运行。如果你可以import你想使用的库,那就这样做吧。 @CharlesDuffy 老实说,我不完全确定为什么,但在我的笔记本电脑上,该命令仅适用于添加了 shell=True 的情况。尽管我在 docker 中运行它以避免必须进行 madgraph 的挑剔安装(这是一个基于时间限制的决定,而不是任何事情)。我可能最初应该提到它。在我的笔记本电脑上运行的原始命令是:subprocess.run('sudo docker run -t -i -v $HOME/outputs:/var/MG_outputs --mount type=bind,source=$HOME/models,target=/app hfukuda/madgraph /home/hep/MG5_aMC_v2_6_3_2/bin/mg5_aMC /app/mg_run.txt', shell=True) 列表应该包含三个元素,而不是两个:['python', './madgraph/bin/mg5_aMC', 'mg_run_iridis.txt'] 【参考方案1】:

试试:

subprocess.run('python ./madgraph/bin/mg5_aMC mg_run_iridis.txt', shell=True)

注意这个run 部分。有关详细信息,请参阅documentaion。目前,您正在尝试调用 subprocess 模块本身,而不是模块中的特定函数。

【讨论】:

不幸的是,我最初在命令中确实有“运行”,它输出以下内容:Traceback (most recent call last): File "MainIridis_script.py", line 42, in &lt;module&gt; the_main_event() File "MainIridis_script.py", line 22, in the_main_event run_madgraph() File "MainIridis_script.py", line 39, in run_madgraph subprocess.run('python ./madgraph/bin/mg5_aMC mg_run_iridis.txt') AttributeError: 'module' object has no attribute 'run' 根据文档,run 函数是在 Python 3.5 中添加的。你用的是什么 Python 版本? 我在笔记本电脑上使用 python 3,但在大学集群上我遇到了一个问题,因为 madgraph 是用 python 2 编写的,我很难在它们之间切换,所以我只是试图将我的脚本转换为 python2。

以上是关于Bash命令在终端中有效,但在python脚本中的“子进程”中无效[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 中使用终端命令将文件参数传递给我的 bash 脚本? [复制]

用于在终端输出中搜索特定单词的Bash脚本

测试命令在终端中有效,但在 php 中无效

Telnet smtp 命令 bash 2.05 脚本问题

如何使用 python send cmd 保持 bash 数组有效 [重复]

将 python 脚本作为命令行变量运行