Python как shell

Материал из Xgu.ru

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

Содержание

[править] Интерактивный интерпретатор Python

[править] Дополнительная информация

[править] Работа с подпроцессами в Python

Вопросы параллельного запуска нескольких подпроцессов подробно разбираются здесь:

[править] Вопросы и ответы

[править] Как максимально облегчить написание shell-подобных программ на Python?

Можно использовать IPython.

Кроме того есть несколько модулей, которые существенно упрощают выполнение стандартных для shell-операций в питоне:


[править] Как нынче правильно считывать данные из внешних программ?

Другими словами, как правильно организовывать pipe?

Раньше для этого можно было использовать функции popen, popen2, popen3 и тому подобные. Сейчас лучше использовать модуль subprocess. Его использовать и проще, и нагляднее.

import subprocess

print '\npopen3:'
proc = subprocess.Popen('cat -; echo ";to stderr" 1>&2',
                        shell=True,
                        stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        )
stdout_value, stderr_value = proc.communicate('through stdin to stdout')
print '\tpass through:', repr(stdout_value)
print '\tstderr:', repr(stderr_value)

Конечно, при таком подходе есть небольшая проблема: данные будут выдаваться не сразу, а все скопом, когда процесс завершится. Кроме того, текущий процесс, в котором вызывается дочерний процесс, будет блокироваться.

Чтобы передавать данные в реальном времени, можно использовать такую конструкцию ([1], Nadia Alramli):

import subprocess
import sys

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

while True:
    out = process.stdout.read(1)
    if out == '' and process.poll() != None:
        break
    if out != '':
        sys.stdout.write(out)
        sys.stdout.flush()

Надя просто читает побайтно поток и выводит его дальше. Конечно, это не очень быстро, если передаётся значительное количество данных. Обойти проблему можно таким образом ([2], Derrick Petzold):

fcntl.fcntl(
    proc.stdout.fileno(),
    fcntl.F_SETFL,
    fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
)

while proc.poll() == None:
    readx = select.select([proc.stdout.fileno()], [], [])[0]
    if readx:
        chunk = proc.stdout.read()
        print chunk

Можно читать не только байты, но и строки с помощью proc.stdout.readline()

Дополнительная информация:

[править] Дополнительная информация

[править] Работа с внешними процессами


[править] А если нужно не только считывать, но и записывать данные, то есть организовать диалог с программой?

Да, есть модули, обладающие функциональностью наподобие expect. Например, модуль pexpect.

import pexpect
child = pexpect.spawn ('ftp ftp.openbsd.org')
child.expect ('Name .*: ')
child.sendline ('anonymous')
child.expect ('Password:')
child.sendline ('noah@example.com')
child.expect ('ftp> ')
child.sendline ('cd pub')
child.expect('ftp> ')
child.sendline ('get ls-lR.gz')
child.expect('ftp> ')
child.sendline ('bye')

Читать данные, которые передаются программе или программой:

child.logfile_read = sys.stdout
child.logfile_send = sys.stdout

Или объединённый:

 child.logfile = sys.stdout


Подробнее:

[править] Как создать программу-демон?


[править] Как написать программу-демон на питоне?

Если у вас есть модуль daemon[1] (реализация PEP-3143), то всё совсем элементарно:

import daemon
from spam import do_main_program

with daemon.DaemonContext():
    do_main_program()

Если же модуль этот по каким-то причинам отсутствует и доустановить его нельзя, то можно воспользоваться кодом отсюда:

[править] Примечания

  1. http://pypi.python.org/pypi/python-daemon/