Python/FAQ/Управление и взаимодействие с процессами

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
· Python ·

Содержание

[править] 16. Process Management and Communication

[править] Gathering Output from a Program

import popen2
 
# other popen methods than popen4 can lead to deadlocks
# if there is much data on stdout and stderr
 
(err_out, stdin) = popen2.popen4("program args")
lines = err_out.read() # collect output into one multiline string
 
 
(err_out, stdin) = popen2.popen4("program args")
lines = err_out.readlines() # collect output into a list, one line per element
 
#-----------------------------
 
(err_out, stdin) = popen2.popen4("program args")
output = []
while True:
    line = err_out.readline()
    if not line:
        break
 
    output.appen(line)
output = ''.join(output)

[править] Running Another Program

import os
myfile = "foo.txt"
status = os.system("vi %s" % myfile)
 
#-----------------------------
import os
os.system("cmd1 args | cmd2 | cmd3 >outfile")
os.system("cmd args <infile >outfile 2>errfile")
 
status = os.system("%s %s %s" % (program, arg1, arg2))
 
if status != 0:
    print "%s exited funny: %s" % (program, status)
    raise SystemExit

[править] Replacing the Current Program with a Different One

# -----------------------------
import os
 
import sys
import glob
 
args = glob.glob("*.data")
try:
    os.execvp("archive", args)
except OSError, e:
    print "Couldn't replace myself with archive: %s" % err
    raise SystemExit
 
# The error message does not contain the line number like the "die" in
# perl. But if you want to show more information for debugging, you can
# delete the try...except and you get a nice traceback which shows all
# line numbers and filenames.
 
# -----------------------------
os.execvp("archive", ["accounting.data"])

[править] Reading or Writing to Another Program

# -------------------------
 
# Read from a child process
 
import sys
import popen2
pipe = popen2.Popen4("program arguments")
pid = pipe.pid
for line in pipe.fromchild.readlines():
    sys.stdout.write(line)
 
 
# Popen4 provides stdout and stderr.
# This avoids deadlocks if you get data
# from both streams.
#
# If you don't need the pid, you
# can use popen2.popen4(...)
 
# -----------------------------
# Write to a child process
 
 
import popen2
 
pipe = popen2.Popen4("gzip > foo.gz")
pid = pipe.pid
pipe.tochild.write("Hello zipped world!\n")
pipe.tochild.close() # programm will get EOF on STDIN

[править] Filtering Your Own Output

class OutputFilter(object):
    def __init__(self, target, *args, **kwds):
        self.target = target
        self.setup(*args, **kwds)
        self.textbuffer = ""
 
    def setup(self, *args, **kwds):
        pass
 
    def write(self, data):
        if data.endswith("\n"):
            data = self.process(self.textbuffer + data)
            self.textbuffer = ""
 
            if data is not None:
                self.target.write(data)
        else:
            self.textbuffer += data
 
    def process(self, data):
        return data
 
 
class HeadFilter(OutputFilter):
    def setup(self, maxcount):
        self.count = 0
        self.maxcount = maxcount
 
    def process(self, data):
        if self.count < self.maxcount:
            self.count += 1
            return data
 
 
class NumberFilter(OutputFilter):
    def setup(self):
        self.count=0
 
    def process(self, data):
        self.count += 1
        return "%s: %s"%(self.count, data)
 
 
class QuoteFilter(OutputFilter):
    def process(self, data):
        return "> " + data
 
 
import sys
f = HeadFilter(sys.stdout, 100)
for i in range(130):
    print>>f, i
 
print
 
txt = """Welcome to Linux, version 2.0.33 on a i686
 
"The software required `Windows 95 or better', 
so I installed Linux." """
f1 = NumberFilter(sys.stdout)
f2 = QuoteFilter(f1)
for line in txt.split("\n"):
    print>>f2, line
print
f1 = QuoteFilter(sys.stdout)
f2 = NumberFilter(f1)
for line in txt.split("\n"):
    print>>f2, line

[править] Preprocessing Input

# This script accepts several filenames
# as argument. If the file is zipped, unzip
# it first. Then read each line if the file
import os
import sys
import popen2
 
for file in sys.argv[1:]:
    if file.endswith(".gz") or file.endswith(".Z"):
        (stdout, stdin) = popen2.popen2("gzip -dc '%s'" % file)
        fd = stdout
    else:
        fd = open(file)
    for line in fd:
        # ....
        sys.stdout.write(line)
    fd.close()
#-----------------------------
 
#-----------------------------
# Ask for filename and open it
import sys
print "File, please?"
line = sys.stdin.readline()
file = line.strip() # chomp
open(file)

[править] Reading STDERR from a Program

# Execute foo_command and read the output
 
import popen2
(stdout_err, stdin) = popen2.popen4("foo_command")
for line in stdout_err.readlines():
    # ....

[править] Controlling Input and Output of Another Program

# Open command in a pipe
# which reads from stdin and writes to stdout
 
import popen2
pipe = popen2.Popen4("wc -l") # Unix command
pipe.tochild.write("line 1\nline 2\nline 3\n")
pipe.tochild.close()
output = pipe.fromchild.read()

[править] Controlling the Input, Output, and Error of Another Program

# popen3: get stdout and stderr of new process
# Attetion: This can lead to deadlock,
# since the buffer of stderr or stdout might get filled.
# You need to use select if you want to avoid this.
 
import popen2
(child_stdout, child_stdin, child_stderr) = popen2.popen3(...)

[править] Communicating Between Related Processes

# @@INCOMPLETE@@
# @@INCOMPLETE@@

[править] Making a Process Look Like a File with Named Pipes

# @@INCOMPLETE@@
# @@INCOMPLETE@@

[править] Sharing Variables in Different Processes

# @@INCOMPLETE@@
# @@INCOMPLETE@@

[править] Listing Available Signals

#
# Print available signals and their value
# See "man signal" "man kill" on unix.
 
import signal
for name in dir(signal):
    if name.startswith("SIG"):
        value = getattr(signal, name)
        print "%s=%s" % (name, value)

[править] Sending a Signal

# You can send signals to processes
# with os.kill(pid, signal)

[править] Installing a Signal Handler

import signal
 
def get_sig_quit(signum, frame):
    ....
 
signal.signal(signal.SIGQUIT, get_sig_quit)   # Install handler
 
signal.signal(signal.SIGINT, signal.SIG_IGN)  # Ignore this signal
signal.signal(signal.SIGSTOP, signal.SIG_DFL) # Restore to default handling

[править] Temporarily Overriding a Signal Handler

# Example of handler: User must Enter Name ctrl-c does not help
 
import sys
import signal
 
def ding(signum, frame):
    print "\aEnter your name!"
    return
 
signal.signal(signal.SIGINT, ding)
print "Please enter your name:"
 
name = ""
while not name:
    try:
        name = sys.stdin.readline().strip()
    except:
        pass
 
print "Hello: %s" % name

[править] Writing a Signal Handler

# @@INCOMPLETE@@
# @@INCOMPLETE@@

[править] Catching Ctrl-C

import signal
 
# ignore signal INT
signal.signal(signal.SIGINT, signal.SIG_IGN)
 
# Install signal handler
def tsktsk(signum, frame):
    print "..."
 
signal.signal(signal.SIGINT, tsktsk)

[править] Avoiding Zombie Processes

# @@INCOMPLETE@@
# @@INCOMPLETE@@

[править] Blocking Signals

# @@INCOMPLETE@@
# @@INCOMPLETE@@

[править] Timing Out an Operation

import signal
 
def handler(signum, frame):
    raise "timeout"
 
signal.signal(signal.SIGALRM, handler)
 
try:
    signal.alarm(5) # signal.alarm(3600)
 
    # long-time operation
    while True:
        print "foo"
 
    signal.alarm(0)
except:
    signal.alarm(0)
    print "timed out"
else:
    print "no time out"

[править] Program: sigrand

# @@INCOMPLETE@@
# @@INCOMPLETE@@