【问题标题】:running command before other finished in python在其他完成之前在 python 中运行命令
【发布时间】:2014-10-07 12:31:01
【问题描述】:

我已经问过了,很少有人给出好的建议,但我还是初学者,对我来说有很多未知数。因此我决定再次寻求帮助而不给出错误代码。

我需要一个脚本,它会在另一个仍在运行时执行将文件复制到目录。 基本上我运行第一个命令,它会生成文件(直到用户按下回车键),然后这些文件就消失了(自动删除)。
我想要的是复制这些文件(也不必按“Enter”)。 我用 bash 制作,但是我想在 python 上实现这一点。请看下面:

while kill -0 $! 2>/dev/null;do
cp -v /tmp/directory/* /tmp/
done

【问题讨论】:

  • 查看subprocessmultiprocessing 模块。
  • 所以第一个脚本在一个目录中生成文件,而您希望第二个脚本将文件移动到另一个目录中,两个脚本并行运行。对 ?但我有一个问题:第二个脚本如何知道第一个脚本已完成文件处理?还是在第一次处理文件时第二次移动文件是无害的?
  • @SergeBallesta 是的,它是无害的。完成生成文件时的第一个脚本实际上是在等待使用“完成复制时按 Enter”来复制它们。然后删除它们。我只想自动完成,无需复制/移动它们,每次都按回车完成。
  • 第一个 script 是命令行界面还是图形用户界面脚本?
  • @SergeBallesta 纯命令行。在 shell 中,您可以使用“&”解决此“按 Enter”并将进程移至后台。我用 os.system 试过这个,但到目前为止没有成功。

标签: python scripting python-multiprocessing


【解决方案1】:

如果第一个脚本是纯命令行:它应该可以用 python 脚本完全管理。

一般架构:

  • python 脚本以subprocess 模块开始第一个
  • 从第一个脚本读取输出,直到收到要求按 Enter 的消息
  • 将所有文件从源目录复制到目标目录
  • \r 发送到第一个脚本输入
  • 等待第一个脚本终止
  • 退出

一般要求:

  • 第一个脚本必须是纯 CLI 脚本
  • 第一个脚本必须写入标准输出/错误并从标准输入读取 - 如果它读取/写入 物理 终端(Unix/Linux 上的/dev/tty 或 Dos/Windows 上的con:) ,它行不通
  • 处理结束必须在标准输出/错误中可识别
  • 如果以上两个要求没有得到满足,唯一的办法就是等待一段定义的时间

可选操作:

  • 如果第一个脚本中还有其他交互(读取和/或写入),则需要在脚本中添加重定向,当然可行,但会有点困难

配置:

  • 要运行的命令
  • 指示第一个程序已完成处理的字符串(来自命令输出)
  • 源目录
  • 目标目录
  • 要复制的文件名的模式
  • 如果时间已定义且输出中没有可识别的字符串:复制前等待的延迟

这样的脚本应该易于编写和测试,并且能够根据需要管理第一个脚本。

编辑:这里是这样一个脚本的一个例子,仍然没有超时管理。

import subprocess
import os
import shutil
import re

# default values for command execution - to be configured at installation
defCommand = "test.bat"
defEnd = "Appuyez"
defSource = "."
defDest = ".."
# BEWARE : pattern is in regex format !
defPattern="x.*\.txt"

class Launcher(object):
    '''
Helper to launch a command, wait for a defined string from stderr or stdout
of the command, copy files from a source folder to a destination folder,
and write a newline to the stdin of the command.
Limits : use blocking IO without timeout'''
    def __init__(self, command=defCommand, end=defEnd, source=defSource,
                 dest=defDest, pattern = defPattern):
        self.command = command
        self.end = end
        self.source = source
        self.dest = dest
        self.pattern = pattern

    def start(self):
        'Actualy starts the command and copies the files'
        found = False
        pipes = os.pipe() # use explicit pipes to mix stdout and stderr
        rx = re.compile(self.pattern)
        cmd = subprocess.Popen(self.command, shell=True, stdin=subprocess.PIPE,
                               stdout=pipes[1], stderr=pipes[1])
        os.close(pipes[1])
        while True:
            txt = os.read(pipes[0], 1024)
            #print(txt) # for debug
            if str(txt).find(self.end) != -1:
                found = True
                break
        # only try to copy files if end string found
        if found:
            for file in os.listdir(self.source):
                if rx.match(file):
                    shutil.copy(os.path.join(self.source, file), self.dest)
                    print("Copied : %s" % (file,))
            # copy done : write the newline to command input
            cmd.stdin.write(b"\n")
        cmd.stdin.close()
        try:
            cmd.wait()
            print("Command terminated with %d status" % (cmd.returncode,))
        except:
            print("Calling terminate ...")
            cmd.terminate()
        os.close(pipes[0])

# allows to use the file either as an imported module or directly as a script
if __name__ == '__main__':
    # parse optional parameters
    import argparse

    parser = argparse.ArgumentParser(description='Launch a command and copy files')
    parser.add_argument('--command', '-c', nargs = 1, default = defCommand,
                        help="full text of the command to launch")
    parser.add_argument('--endString', '-e', nargs = 1, default = defEnd,
                        dest="end",
                        help="string that denotes that command has finished processing")
    parser.add_argument('--source', '-s', nargs = 1, default = defSource,
                        help="source folder")
    parser.add_argument('--dest', '-d', nargs = 1, default = defDest,
                        help = "destination folder")
    parser.add_argument('--pattern', '-p', nargs = 1, default = defPattern,
                        help = "pattern (regex format) for files to be copied")

    args = parser.parse_args()

    # create and start a Launcher ...
    launcher = Launcher(args.command, args.end, args.source, args.dest,
                        args.pattern)
    launcher.start()

【讨论】:

  • 有一个进度条,完成后等待回车 - 在此期间,您可以将文件复制到另一个位置。我真的不知道如何“模仿输入”。在bash中没有问题,它会自己跳过。
  • 很抱歉,如果您没有对问题给出清晰的描述,我将无法为您提供帮助。什么存在,什么是可修改的,什么是你想要实现的?
  • 好的,抱歉不够清楚。 1.第一个命令在/tmp/下生成文件olear1.txt。进度条显示进度。完成后,达到100%。我们看到 /tmp/olear1.txt 存在。但是,在进度条脚本(生成者)等待之后:按 Enter 键完成,然后从 /tmp/ 中删除文件。我们可以在此期间从 /tmp 复制/移动文件,同时等待按 enter 并且它是无害的。但是,用户始终需要在最后按 Enter 键才能完成脚本。
  • 我想将这些文件复制到另一个目录,然后自行按下“Enter”。我想把所有这些任务放在一个脚本中
  • 你能去掉按回车完成和从第一个脚本中删除文件吗?
猜你喜欢
  • 1970-01-01
  • 2015-08-04
  • 2018-07-17
  • 1970-01-01
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
相关资源
最近更新 更多