【问题标题】:Python: Run bash command with redirection in background and get the process idPython:在后台运行带有重定向的bash命令并获取进程ID
【发布时间】:2017-05-22 07:28:25
【问题描述】:

我正在使用来自Centos 6 平台的Python 2.6.6

我需要在后台从 Python 运行一个包含重定向运算符的 bash 命令,并且需要从子进程对象中读取后台进程的 pid。

我试过下面的代码sn-ps,但是还是不行。

我的代码

import subprocess

# Below code throws child_exception
myProcess = subprocess.Popen('tail -f -n 0 /home/user123/mainFile.txt >> /home/user123/tailFile.txt &', subprocess.PIPE)

#If I use the below command, terminating the process kills
#only the shell process and leaves the tail process as orphan
myProcess = subprocess.Popen('tail -f -n 0 /home/user123/mainFile.txt >> /home/user123/tailFile.txt', shell=True, subprocess.PIPE)

cmd = ['tail', '-f', '-n', '0', '/home/user123/mainFile.txt', '>>', '/home/user123/tailFile.txt', '&']
#Below line throws bash error saying: "cannot open file '>>'"
myProcess = subprocess.Popen(cmd, stdout=subprocess.PIPE)

myProcessPid = myProcess.communicate()[0]

最后我需要获取在后台运行的尾部进程的 pid。

【问题讨论】:

  • >>, & 是 shell 元字符;除非您将shell=Truesubprocess.Popen 一起使用,否则它不会使用shell,并且这些元字符将被逐字解释......
  • 我尝试使用shell=True 并尝试将其作为列表和字符串提供。我能够获得正确的进程 ID,但在 bash 中只启动没有任何参数的尾部进程。

标签: python linux bash subprocess


【解决方案1】:

在 python 中包装纯 shell 既无用也不明智。

subprocess.Popen 对象有自己的方式进行重定向和类似的事情,而不是依靠外壳。这是一个例子。

 import subprocess
 with open("ls.output.txt", "w") as f:
     # This is the way you'd run "ls -al > ls.output.txt" in the background
     p = subprocess.Popen(["ls", "-al"], stdout=f) # This will run in the background

 p.wait() # Wait till process completes

 with open("ls.output.txt") as f:
        print (f.readline()) # Will print first line of ls -al output (total 2657828)

【讨论】:

  • 但我想启动包含重定向 > / >> 运算符的 bash 命令,并且正常终止
  • 你为什么要这么做?
  • 因为我希望我的尾部输出被重定向到另一个文件中
  • @Ashwin 你没有读懂他说的话。打开文件并使用 subprocess.Popen()stdout 选项将数据提供给它。如果您以附加模式打开文件,则 Popen() 进程的输出将附加到文件中。您可以优雅地终止 Popen.terminate() 方法。但是你也不需要 tail 来做这些。
  • 感谢@NoufalIbrahim。我尝试使用 open () as filePtr: 方法而不是 shell 类型重定向,它工作正常。
【解决方案2】:

除非将 shell=True 传递给您的 subprocess.Popen() 调用,否则不会执行这些重定向。更好的方法是使用 stdout=subprocess.PIPE 选项并自己捕获输出。

shell 通常会为您进行重定向。并且将命令分解为命令和参数的向量(列表)的交易是针对命令的,因为 shell 会将这些传递给 execve() 系统调用。 shell 重定向、管道和其他操作符不是其中的一部分。

您也不需要 & 运算符,因为您的 subprocess.Popen() 进程会在后台自动运行。它可能在 I/O 上被阻塞,您可以从 suprocess.PIPE 轮询和读取它。

更重要的是,您根本不必使用运行 tail 命令的子进程。如果您只想跟随文件的结尾,您可以使用 file.seek()file.tell()file.readline( )os.fstat() 方法。

这是一个直接在 Python 中实现 tail -f 语义的简单类:

#!/usr/bin/env python
from __future__ import print_function
import os, time

class Tail(object):
    def __init__(self, filename):
        self.fd = open(fn, 'r')  # file descriptor
        self.off = self.fd.seek(0, 2)  # end of file: skip the previous contents
        self.buff = list()
        self.last_line = 0
        self.sz = os.fstat(self.fd.fileno()).st_size

    def sleep(self):
        self.off = self.fd.tell()
        while self.sz - self.off == 0:
            self.sz = os.fstat(self.fd.fileno()).st_size
            time.sleep(0.1)

    def follow(self):
        while self.sz - self.off > 0:
            self.buff.append(self.fd.readline())
            self.off = self.fd.tell()
            self.sz = os.fstat(self.fd.fileno()).st_size

    def fetch(self):
        end = self.last_line
        self.last_line = len(self.buff)
        return '\n'.join(self.buff[end:])

...下面是一些使用它的示例代码:

if __name__ == '__main__':
    import sys

    if len(sys.argv[1:]) < 1:
        print('Must supply filename', file=sys.stderr)
        sys.exit(1)
    fn = sys.argv[1]

    tail = Tail(fn)
    while True:
        print('... sleeping ...')
        tail.sleep()
        tail.follow()
        print(tail.fetch())

...它显示了一种使用方式。

我不会使用这个类。我会将 Tail.sleep() 更改为 Tail.poll() ,这将立即返回一个值,指示文件末尾是否有数据准备就绪。我还将使用Python Standard Library: select module 进行轮询和睡眠。然后,您可以同时维护一个您要跟踪的文件列表。此外,不断增长的 Tail.buff 也会成为问题;我要么在每次提取后自动刷新它,要么添加一个方法来刷新它。

【讨论】:

  • 顺便说一句,我还编写了一个简单的 sn-p 代码来使用 Python mmap 模块执行类似的操作:quora.com/… ... 必须对其进行修改以在每个模块上返回所有新行民意调查。
猜你喜欢
  • 1970-01-01
  • 2011-12-02
  • 2018-02-23
  • 2011-08-29
  • 2012-02-25
  • 1970-01-01
  • 2015-06-19
  • 1970-01-01
相关资源
最近更新 更多