【问题标题】:subprocess.call() or subprocess.Popen for generating/using output filessubprocess.call() 或 subprocess.Popen 用于生成/使用输出文件
【发布时间】:2016-11-30 08:28:47
【问题描述】:

我正在尝试编写 Python 代码来与另一个使用命令行提示符的软件进行交互。执行命令行提示后,目录中会生成多个输出文件,软件使用这些输出文件进行一些计算。另外,我的程序的其余部分使用了这些输出文件。目前,我运行我的python代码,然后在命令行提示符中手动输入,然后调用我的其余代码并且工作正常,但是当我尝试输入时:

subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=False)

进入我的文件,它没有正确执行(没有生成输出文件)。

当我编写上面的代码时,它是自己的单独 python 代码,并在我的代码的第一部分之后立即调用它 - 它也有效。

根据我的输出,我确信问题出在:调用生成了多个文件,然后使用这些文件进行计算,但是,它没有生成正确的文件,所以我的输出出现错误。因此,在某种程度上,它似乎超前了:在进行计算之前不等待生成输出文件,但是当我在程序之外单独运行此命令时,它再次起作用。关于为什么会发生这种情况的任何想法?

我做错了什么?我需要指定目录吗(输出文件可以放在我电脑的其他地方吗)?我需要使用 subprocess.Popen 吗?我在互联网上搜索过,但我对 Python 很陌生,完全被难住了。

欢迎提出任何建议。谢谢!

编辑:对于那些询问的人,这里是 sfit4Layer0.py 代码:

#! /usr/bin/python
##! /usr/local/python-2.7/bin/python
##! /usr/bin/python
##! /usr/bin/python
# Change the above line to point to the location of your python executable
#----------------------------------------------------------------------------------------
# Name:
#        sfit4Layer0.py
#
# Purpose:
#       This file is the zeroth order running of sfit4. It accomplishes the following:
#           1) Calls pspec to convert binary spectra file (bnr) to ascii (t15asc)
#           2) Calls hbin to gather line parameters from hitran
#           3) Calls sfit4
#           4) Calls error analysis from Layer1mods.py
#           5) Clean outputs from sfit4 call
#
#
# External Subprocess Calls:
#           1) pspec executable file from pspec.f90
#           2) hbin  executable file from hbin.f90
#           3) sfit4 executable file from sfit4.f90
#                       4) errAnalysis from Layer1mods.py
#
#
#
# Notes:
#   1) Options include:
#            -i <dir>     : Optional. Data directory. Default is current working directory
#            -b     <dir/str> : Optional. Binary directory. Default is hard-code.
#            -f <str>     : Run flags, h = hbin, p = pspec, s = sfit4, e = error analysis, c = clean
#
#
# Usage:
#       ./sfit4Layer0.py [options]
#
#
# Examples:
#       1) This example runs hbin, pspec, sfit4, error analys, and cleans working directory prior to execution
#           ./sfit4Layer0.py -f hpsec
#
#       2) This example just runs sfit4
#           ./sfit4Layer0.py -f s
#
#       3) This example cleans the output file created by sfit4 in directory (/User/home/datafiles/) which is not the current directory
#          ./sfit4Layer0.py -i /User/home/datafiles/ -f c
#
# Version History:
#       Created, May, 2013  Eric Nussbaumer (ebaumer@ucar.edu)
#
#
# License:
#    Copyright (c) 2013-2014 NDACC/IRWG
#    This file is part of sfit4.
#
#    sfit4 is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    any later version.
#
#    sfit4 is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with sfit4.  If not, see <http://www.gnu.org/licenses/>
#
#----------------------------------------------------------------------------------------


#---------------
# Import modules
#---------------
import sys
import os
import getopt
import sfitClasses as sc
from Layer1Mods import errAnalysis
from Tkinter import Tk
from tkFileDialog import askopenfilename


#------------------------
# Define helper functions
#------------------------
def usage(binDirVer):
        print 'sfit4Layer0.py -f <str> [-i <dir> [-b <dir/str> ] \n'
        print '-i <dir>     Data directory. Optional: default is current working directory'
        print '-f <str>     Run Flags: Necessary: h = hbin, p = pspec, s = sfit4, e = error analysis, c = clean'
        print '-b <dir/str> Binary sfit directory. Optional: default is hard-coded in main(). Also accepts v1, v2, etc.'
        for ver in binDirVer:
                print '             {}: {}'.format(ver,binDirVer[ver])        

        sys.exit()


def main(argv):

        #----------------
        # Initializations
        #----------------
         #------------
         # Directories
         #------------
        wrkDir    = os.getcwd()                              # Set current directory as the data directory
        binDir    = '/data/bin'                              # Default binary directory. Used of nothing is specified on command line
        binDirVer = {
        'v1':   '/data/ebaumer/Code/sfit-core-code/src/',    # Version 1 for binary directory (Eric)
        'v2':   '/data/tools/400/sfit-core/src/',             # Version 2 for binary directory (Jim)
        'v3':   '/Users/jamesw/FDP/sfit/400/sfit-core/src/',             # Version 2 for binary directory (Jim)
        'v4':   '/home/ebaumer/Code/sfit4/src/',
        'v5':   '/Users/allisondavis/Documents/Summer2016/sfit4_0.9.4.3/src'
        }


         #----------
         # Run flags
         #----------
        hbinFlg  = False                                          # Flag to run hbin
        pspecFlg = False                                          # Flag to run pspec
        sfitFlg  = False                                          # Flag to run sfit4
        errFlg   = False                                          # Flag to run error analysis
        clnFlg   = False                                          # Flag to clean directory of output files listed in ctl file

        #--------------------------------
        # Retrieve command line arguments
        #--------------------------------
        try:
                opts, args = getopt.getopt(sys.argv[1:], 'i:b:f:?')

        except getopt.GetoptError as err:
                print str(err)
                usage(binDirVer)
                sys.exit()

        #-----------------------------
        # Parse command line arguments
        #-----------------------------
        for opt, arg in opts:
                # Data directory
                if opt == '-i':
                        wrkDir = arg
                        sc.ckDir(wrkDir,exitFlg=True)

                # Binary directory
                elif opt == '-b':
                        if not sc.ckDir(arg,exitFlg=False,quietFlg=True):
                                try:             binDir = binDirVer[arg.lower()]
                                except KeyError: print '{} not a recognized version for -b option'.format(arg); sys.exit()

                        else: binDir = arg

                        if not(binDir.endswith('/')): binDir = binDir + '/'

                # Run flags
                elif opt == '-f':
                        flgs = list(arg)
                        for f in flgs:
                                if   f.lower() == 'h': hbinFlg  = True
                                elif f.lower() == 'p': pspecFlg = True
                                elif f.lower() == 's': sfitFlg  = True
                                elif f.lower() == 'e': errFlg   = True
                                elif f.lower() == 'c': clnFile  = True
                                else: print '{} not an option for -f ... ignored'.format(f)
                elif opt == '-?':
                        usage(binDirVer)
                        sys.exit()                        

                else:
                        print 'Unhandled option: {}'.format(opt)
                        sys.exit()

        #--------------------------------------
        # If necessary change working directory
        # to directory with input data.
        #--------------------------------------
        if os.path.abspath(wrkDir) != os.getcwd(): os.chdir(wrkDir)
        if not(wrkDir.endswith('/')): wrkDir = wrkDir + '/'

        #--------------------------
        # Initialize sfit ctl class
        #--------------------------
        ctlFileName = wrkDir + 'sfit4.ctl'
        if sc.ckFile(wrkDir+'sfit4.ctl'): ctlFileName = wrkDir + 'sfit4.ctl'
        else:
                Tk().withdraw()
                ctlFileName = askopenfilename(initialdir=wrkDir,message='Please select sfit ctl file')

        ctlFile = sc.CtlInputFile(ctlFileName)
        ctlFile.getInputs()

        #------------------------
        # Initialize sb ctl class
        #------------------------
        if errFlg:
                if sc.ckFile(wrkDir+'sb.ctl'): sbCtlFileName = wrkDir + 'sb.ctl'
                else:
                        TK().withdraw()
                        sbCtlFileName = askopenfilename(initialdir=wrkDir,message='Please select sb ctl file')

                sbCtlFile = sc.CtlInputFile(sbCtlFileName)
                sbCtlFile.getInputs()

        #---------------------------
        # Clean up output from sfit4
        #---------------------------
        if clnFlg:
                for k in ctlFile.inputs['file.out']:
                        if 'file.out' in k:
                                try:            os.remove(wrkDir + ctlFile.inputs[k])
                                except OSError: pass

        #----------
        # Run pspec
        #----------
        if pspecFlg:
                print '*************'
                print 'Running pspec'
                print '*************'
                rtn = sc.subProcRun( [binDir + 'pspec'] )

        #----------
        # Run hbin
        #----------
        if hbinFlg:
                print '************'
                print 'Running hbin'
                print '************'
                rtn = sc.subProcRun( [binDir + 'hbin'] )

        #----------
        # Run sfit4
        #----------
        if sfitFlg:
                print '************'
                print 'Running sfit'
                print '************'
                rtn = sc.subProcRun( [binDir + 'sfit4'] )

        #-------------------
        # Run error analysis
        #-------------------
        if errFlg:
                print '**********************'
                print 'Running error analysis'
                print '**********************'
                rtn = errAnalysis(ctlFile,sbCtlFile,wrkDir)



if __name__ == "__main__":
        main(sys.argv[1:])

【问题讨论】:

  • 您是否检查过一个程序是否在同时运行的同时在另一个文件中打开时不尝试打开文件?
  • 我如何检查这个?还是允许它这样做?这就是我认为可能的问题
  • 这取决于您的程序的行为,如果他们只使用一次文件,请确保在其他程序中打开之前file.close(),但如果您必须同时检查同一个文件不同的程序我建议你使用共享内存技术
  • @lu1her 非常感谢您的帮助 - 您是否恰好有相关信息的链接?
  • 程序是否改变了当前工作目录?你可以在运行命令之前print('os.getcwd())

标签: python subprocess


【解决方案1】:

试试看:subprocess.call('sfit4Layer0.py -bv5 -fs', shell=True)

【讨论】:

    【解决方案2】:

    如果您尝试从您的 python 脚本调用另一个 python 脚本,则 subprocess.call() 方法适合您的操作。

    我建议你转

    subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=True)
    

    希望这个解决方案有效。

    当您想要将 STDIN/STDOUT 或 STDERR 从一个进程传送到另一个进程时,通常使用 Popen。

    此外,当您编写文件时,请确保将文件或目录路径创建为绝对路径,这将帮助您始终将文件放置在您想要的位置。

    快乐编码。

    【讨论】:

      【解决方案3】:
      subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=False)
      
      1. 假设 sfit4Layer0.py 是可执行的,但它可能不是
      2. 假设 sfit4Layer0.py 包含 #!/usr/bin/python shebang,但它可能不包含。

      如果脚本确实包含 shebang 并且不可执行 试试:

      subprocess.call(['python','/path/to/script/sfit4Layer0.py','-bv5','-fs'], shell=False)
      

      如果脚本是可执行的并且包含 shebang 试试:

      subprocess.call(['/path/to/script/sfit4Layer0.py -bv5 -fs'], shell=True)
      

      【讨论】:

      • 这些都不起作用:/根据我的输出,我确信问题在于:调用生成了多个文件,然后使用这些文件进行计算,但是,它没有生成正确的文件,所以我的输出中出现错误。因此,在某种程度上,它似乎超前了:在进行计算之前不等待生成输出文件,但是当我在程序之外单独运行此命令时,它再次起作用。关于为什么会发生这种情况的任何想法?
      • 在这种情况下使用 Popen().wait 却看不到被调用脚本中的代码,这很难说。见:stackoverflow.com/questions/15107714/…
      • 您是否尝试过打印调试代码以查看被调用脚本中的进度。打印是一种非常棒的调试工具。
      • 有趣的是,当我这样做时 p = subprocess.call(['sfit4Layer0.py', '-bv5', '-fs'], shell=False) # 我认为这写了摘要文件 p .wait() 我收到错误“AttributeError: 'int' object has no attribute 'wait'” ... subprocess.call 应该是一个 int 值吗?
      • 你没有阅读我给你的那个链接! subprocess.Popen(....).wait 不是 subprocess.call()。贴出 sfit4Layer0.py 的代码。没有它,我们就在风中撒尿。
      猜你喜欢
      • 2015-05-20
      • 2018-01-14
      • 2013-01-18
      • 2011-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-24
      相关资源
      最近更新 更多