简体   繁体   English

Python:在后台运行带有重定向的bash命令并获取进程ID

[英]Python: Run bash command with redirection in background and get the process id

I am using Python 2.6.6 from Centos 6 platform. 我正在使用来自Centos 6平台的Python 2.6.6

I need to run a bash command from Python in background which contains redirection operators and need to read the background process's pid from the sub-process object. 我需要在后台从Python运行bash命令,其中包含重定向运算符,并且需要从子流程对象读取后台进程的pid。

I have tried the following code snippets, but it is not working. 我已经尝试了以下代码片段,但无法正常工作。

My Code : 我的代码

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]

At the end I need to get the tail process's pid which is running in background. 最后,我需要获取在后台运行的tail进程的pid。

It's not useful or wise to wrap pure shell in python. 将纯壳包装在python中是没有用或明智的。

The subprocess.Popen object has ways of doing redirection and things like that by itself rather than by relying on a shell. subprocess.Popen对象具有进行重定向和类似操作的方式,而不是依靠shell本身。 Here's one example. 这是一个例子。

 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)

These redirections won't be performed unless shell=True is passed to your subprocess.Popen() call. 除非将shell = True传递给subprocess.Popen()调用,否则不会执行这些重定向。 The better way to do it is to use the stdout=subprocess.PIPE option and capture the output yourself. 更好的方法是使用stdout = subprocess.PIPE选项并自己捕获输出。

The shell normally does the redirection for you. Shell通常为您执行重定向。 and this deal where you break the command up into a vector (list) of command and arguments is for the command as the shell would have passed those to an execve() system call. 这是将命令分解为命令和参数的向量(列表)的过程,因为shell会将那些命令传递给了execve()系统调用。 The shell redirection, piping, and other operators aren't part of that. Shell重定向,管道和其他运算符不属于其中。

Also you don't need the & operator as your subprocess.Popen() process is automatically running in the background. 另外,您不需要&运算符,因为您的进程.Popen()进程会在后台自动运行。 It may be blocked on I/O, and you can poll and read that from the suprocess.PIPE . 它可能在I / O上被阻止,您可以从suprocess.PIPE中轮询并读取它。

More to the point you don't have to use a subprocess running the tail command at all. 更重要的是,您根本不需要使用运行tail命令的子流程。 If you just want to follow the end of the file you can do that using the file.seek() , file.tell() , file.readline() and the os.fstat() methods. 如果只想跟踪文件的末尾,则可以使用file.seek()file.tell()file.readline()os.fstat()方法来完成。

Here's a simple class which implements tail -f semantics directly in Python: 这是一个简单的类,直接在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:])

... and here's some sample code using it: ...这是一些使用它的示例代码:

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())

... which shows one way of using it. ...显示了一种使用方式。

I wouldn't use this class. 我不会使用此类。 I'd change Tail.sleep() to Tail.poll() which would just immediately return a value indicating whether there's data ready at the end of the file. 我将Tail.sleep()更改为Tail.poll() ,这将立即返回一个值,该值指示文件末尾是否有数据就绪。 I'd also use the Python Standard Library: select module for the polling and sleep. 我还将使用Python标准库:用于轮询和睡眠的select模块 Then you could maintain a list of files that you're tailing all at once. 然后,您可以维护一次拖尾的文件列表。 Also the endlessly growing Tail.buff would be a problem; 不断增长的Tail.buff也将是一个问题; I'd either flush it automatically after each fetch or I'd add a method to flush it. 我要么在每次获取后自动刷新它,要么添加一个方法来刷新它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM