簡體   English   中英

Python:在后台運行帶有重定向的bash命令並獲取進程ID

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

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

我需要在后台從Python運行bash命令,其中包含重定向運算符,並且需要從子流程對象讀取后台進程的pid。

我已經嘗試了以下代碼片段,但無法正常工作。

我的代碼

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]

最后,我需要獲取在后台運行的tail進程的pid。

將純殼包裝在python中是沒有用或明智的。

subprocess.Popen對象具有進行重定向和類似操作的方式,而不是依靠shell本身。 這是一個例子。

 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)

除非將shell = True傳遞給subprocess.Popen()調用,否則不會執行這些重定向。 更好的方法是使用stdout = subprocess.PIPE選項並自己捕獲輸出。

Shell通常為您執行重定向。 這是將命令分解為命令和參數的向量(列表)的過程,因為shell會將那些命令傳遞給了execve()系統調用。 Shell重定向,管道和其他運算符不屬於其中。

另外,您不需要&運算符,因為您的進程.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標准庫:用於輪詢和睡眠的select模塊 然后,您可以維護一次拖尾的文件列表。 不斷增長的Tail.buff也將是一個問題; 我要么在每次獲取后自動刷新它,要么添加一個方法來刷新它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM