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

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

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

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