【问题标题】:Pipe subprocess to a file in Linux在 Linux 中将子进程通过管道传输到文件
【发布时间】:2017-03-22 06:32:11
【问题描述】:

我正在努力让我的代码正常工作。本质上,我编写了一个将由 cron 调用的 python 脚本。该脚本每周运行一次以执行数据库维护。我的 python 脚本将调用执行实际维护的 perl 脚本。我不得不以这种方式构建它,因为 perl 脚本将总共运行 9 次。有 3 个不同类别的 DB 项,每个类别需要来自 perl 脚本的 3 个不同操作。如果任何类别中的单个操作失败,脚本将从该类别中断并移至下一个(每个操作都依赖于前一个操作)。

我的脚本无法正确执行,我不知道为什么。我正在尝试对其进行故障排除,但我的日志记录逻辑也无法正常工作。我在日志文件中得到的唯一输出是简单的“打印”命令,这些命令是我写到脚本中用于表示和格式化的。

我可以直接从 CLI 很好地运行 perl 脚本,但是从我的 python 脚本调用时它无法正确运行。谁能指出我正确的方向吗?

编辑: 在回答一个问题时,我没有很好地解释 perl 脚本是如何失败的。我没有从 perl 脚本中获取 stdout 或 stderr 到我的日志文件中,所以我还不知道它为什么会失败。 我没有创建 perl 脚本,它是由我管理的软件套件提供的。

这是日志文件输出:

------------------------------------------------------------------------------------------------------
Weekly Voyence archival, deletion, and purging of jobs, events, and revisions beginning at 14:46:11
Block failed, continuing to next block
------
Block failed, continuing to next block
------
Block failed, continuing to next block
------
Weekly Voyence archival, deletion, and purging of jobs, events, and revisions complete at 14:46:11

这是从 CLI 运行 perl 脚本的输出(没有错误):

Script started at Mon Nov  7 14:59:53 2016

Archving/Pruning 0 Parent jobs older than 90 days...
Archving/Pruning 0 Child Jobs older than 90 days...

No Records avaialble for archive..jobs Exiting
Script Completed.

The database utility console log can be found at /opt/voyence/tools/db-   utility/logs/dbutil_console.log

Script exited at Mon Nov  7 14:59:58 2016

这里是python脚本:

#! /usr/bin/python
import sys
import time
import os
import subprocess
def SubProcessCaller(PATH,CallLoad,LogObj,LOGFILE):
    try:
        # subprocess.Popen(["/usr/bin/perl", "-i", "/opt/voyence/tools/db-    utility/database-utility.pl", CallLoad], stderr=LogObj.write, stdout=LogObj.write, shell=true)
        concatvar = "/usr/bin/perl -I /opt/voyence/tools/db-utility/common /opt/voyence/tools/db-utility/database-utility.pl" + CallLoad + " >> " + LOGFILE
        subprocess.check_output(concatvar.split(), shell=True)
        return True
    except:
        LogObj.write("Block failed, continuing to next block" "\n")
        return False

if __name__ == "__main__":

    #DECLARE VARIABLES AND OBJECTS
    TIME = time.strftime("%H:%M:%S")
    PATH = "/opt/voyence/tools/db-utility/database-utility.pl"
    DATE = time.strftime("%Y%m%d")
    LOGFILE = "/var/log/voyence-archive/" + DATE + "voyence-archive.log"
    LOG = open(LOGFILE, "a+")
    #CREATE NEW LOG FILE
    LOG.write("------------------------------------------------------------------------------------------------------\n")
    LOG.write("Weekly Voyence archival, deletion, and purging of jobs, events, and revisions beginning at " + TIME + "\n")
    #JOB ARCHIVAL, DELETION, AND PURGING
    JobActionsDict = [" archive jobs 90"," delete jobs 90"," purge jobs 275"]
    #EVENT ARCHIVAL, DELETION, AND PURGING
    EventActionsDict = [" archive events all 90"," delete events all 90"," purge events all 275"]
    #REVISION ARCHIVAL, DELETION, AND PURGING
    RevisionActionsDict = [" archive revisions 40"," purge revisions 60","  delete revisions '3 months' 40"]

    ActionsTuple = (JobActionsDict, EventActionsDict, RevisionActionsDict)

    for dict in ActionsTuple:
        for item in dict:
            SPCBool = SubProcessCaller(PATH,item,LOG,LOGFILE)
            if SPCBool == False:
                break
        LOG.write("------\n")
    #CLOSE AFTER ALL LOGS HAVE BEEN WRITTEN
    LOG.write("Weekly Voyence archival, deletion, and purging of jobs, events, and revisions complete at " + TIME + "\n")
    LOG.close()

【问题讨论】:

  • 它是怎么失败的?怎么了?有输出吗?您需要包含更多详细信息。你可以edit你的问题。 Perl 程序不是您自己编写的,是吗?它要么已经存在,要么随您使用的任何软件一起提供。
  • check_output 返回命令的输出,但这对于已经将其输出写入文件的命令没有多大意义。你可以改用subprocess.call
  • @simbabque - 感谢您的反馈。我添加了一些额外的细节来回答你的问题。
  • @chepner - 我最初使用了 subprocess.call ,我以为我已经将其注释掉了,但显然我将它从脚本中删除了。 .call 的结果与我从 .check_output 得到的结果相同
  • 另外,不要捕获一个裸异常或忽略实际异常。使用except Exception as exc:,然后至少将异常写入日志文件(或直接写入标准错误),以便查看实际问题。

标签: python linux bash perl


【解决方案1】:
concatvar = "/usr/bin/perl -I /opt/voyence/tools/db-utility/common /opt/voyence/tools/db-utility/database-utility.pl" + CallLoad + " >> " + LOGFILE

这将您的程序名称 (database-utility.pl) 与 CallLoad 变量的内容连接起来 - 在它们之间没有空格。因此,除非CallLoad 中的值以空格开头,否则您实际上会寻找一个名为database-utility.plWhateverIsInCallLoad 的程序。

【讨论】:

  • 是的,我考虑了间距。在actions dicts中,作为调用加载传递的每个参数前面都有一个空格。
  • 是的,我现在明白了。我知道这不会导致您的问题。但是,将空格放在我上面引用的行中(它的存在是有意义的)而不是在每个单独的论点中(它的存在是一个谜)不是更好吗?
  • 是的,我同意你的想法。你的改变很有意义。我想我现在将其纳入。
【解决方案2】:

未经测试,但更惯用的 Python。主要更改是在调用 Perl 脚本时完全绕过 shell,并记录subprocess.call 可能引发的任何错误以帮助调试问题。 (考虑改用logging 模块,但这已经有足够的变化了。)

#! /usr/bin/python
import sys
import time
import os
import subprocess

def subprocess_caller(path, call_load, log_obj):
    subprocess.call(["/usr/bin/perl",
                     "-I",
                     "/opt/voyence/tools/db-utility/common",
                     path,
                     call_load],
                     stdout=log_obj)

log_header = """\
------------------------------------------------------------------------------------------------------
Weekly Voyence archival, deletion, and purging of jobs, events, and revisions beginning at %s
""" %(time.strftime("%H:%M:%S"),)

if __name__ == "__main__":

    #declare variables and objects
    path = "/opt/voyence/tools/db-utility/database-utility.pl"
    logfile = time.strftime("/var/log/voyence-archive/%Y%m%dvoyence-archive.log")

    #create new log file
    with open(logfile, "a+") as log:
        log.write(hog_header)
        #job archival, deletion, and purging
        job_actions = [" archive jobs 90"," delete jobs 90"," purge jobs 275"]
        #event archival, deletion, and purging
        event_actions = [" archive events all 90"," delete events all 90"," purge events all 275"]
        #revision archival, deletion, and purging
        revision_actions = [" archive revisions 40"," purge revisions 60","  delete revisions '3 months' 40"]

        actions = job_actions + event_actions + revision_action:

        for action_type in actions:
            for item in action_type:
                try:
                    subprocess_caller(path, item, log)
                except Exception as exc:
                    log_obj.write(exc + "\n")
                    log_obj.write("Block failed, continuing to next block\n")
                    break
                log.write("------\n")

        log.write("Weekly Voyence archival, deletion, and purging of jobs, events, and revisions complete at %s\n" %
                  (time.strftime("%H:%M:%S"),))

【讨论】:

  • 感谢原型。我对自己进行了一些更改,以纠正出现的一些错误。我的开发盒上有我认为可行的脚本,今晚我将让它作为 cron 作业运行,看看它的行为如何。我会让你知道结果如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 2011-01-14
  • 1970-01-01
  • 2011-06-28
  • 2014-02-03
相关资源
最近更新 更多