Рубрики
Без рубрики

subprocess – порождение дополнительных процессов

Автор оригинала: Doug Hellmann.

Цель:

Запускайте дополнительные процессы и общайтесь с ними.

Модуль subprocess поддерживает три API для работы с процессами. Функция run () , добавленная в Python 3.5, представляет собой высокоуровневый API для запуска процесса и, при необходимости, сбора его вывода. Функции call () , check_call () и check_output () – это бывший высокоуровневый API, перенесенный из Python 2. Они все еще поддерживаются и широко используются в существующих программах. Класс Popen – это низкоуровневый API, используемый для создания других API и полезный для более сложных взаимодействий процессов. Конструктор для Popen принимает аргументы для настройки нового процесса, чтобы родитель мог взаимодействовать с ним по каналам. Он обеспечивает все функции других модулей и функций, которые он заменяет, и многое другое. API единообразен для всех видов использования, и многие из необходимых дополнительных шагов (таких как закрытие дополнительных файловых дескрипторов и обеспечение закрытия каналов) «встроены», а не обрабатываются кодом приложения отдельно.

Модуль subprocess предназначен для замены таких функций, как os.system () , os.spawnv () , вариантов popen () в модулях os и popen2 , а также в модуле commands () . Чтобы упростить сравнение subprocess с этими другими модулями, многие примеры в этом разделе воссоздают те, которые использовались для os и popen2 .

Примечание

API для работы в Unix и Windows примерно одинаков, но основная реализация отличается из-за разницы в моделях процессов в операционных системах. Все показанные здесь примеры были протестированы в Mac OS X. Поведение в ОС, отличной от Unix, может отличаться.

Запуск внешней команды

Чтобы запустить внешнюю команду, не взаимодействуя с ней так же, как os.system () , используйте функцию run () .

subprocess_os_system.py

import subprocess

completed  subprocess.run(['ls', '-1'])
print('returncode:', completed.returncode)

Аргументы командной строки передаются в виде списка строк, что позволяет избежать необходимости экранирования кавычек или других специальных символов, которые могут быть интерпретированы оболочкой. run () возвращает экземпляр CompletedProcess с информацией о процессе, такой как код выхода и выходные данные.

$ python3 subprocess_os_system.py

index.rst
interaction.py
repeater.py
signal_child.py
signal_parent.py
subprocess_check_output_error_trap_output.py
subprocess_os_system.py
subprocess_pipes.py
subprocess_popen2.py
subprocess_popen3.py
subprocess_popen4.py
subprocess_popen_read.py
subprocess_popen_write.py
subprocess_run_check.py
subprocess_run_output.py
subprocess_run_output_error.py
subprocess_run_output_error_suppress.py
subprocess_run_output_error_trap.py
subprocess_shell_variables.py
subprocess_signal_parent_shell.py
subprocess_signal_setpgrp.py
returncode: 0

Установка аргумента shell в истинное значение приводит к тому, что subprocess порождает промежуточный процесс оболочки, который затем запускает команду. По умолчанию команда запускается напрямую.

subprocess_shell_variables.py

import subprocess

completed  subprocess.run('echo $HOME', shellTrue)
print('returncode:', completed.returncode)

Использование промежуточной оболочки означает, что переменные, шаблоны глобусов и другие специальные функции оболочки в командной строке обрабатываются до запуска команды.

$ python3 subprocess_shell_variables.py

/Users/dhellmann
returncode: 0

Примечание

Использование run () без передачи эквивалентно использованию call () , который возвращает только код выхода из процесса.

Обработка ошибок

Атрибут returncode для CompletedProcess – это код выхода программы. Вызывающий отвечает за его интерпретацию для обнаружения ошибок. Если аргумент check для run () имеет значение True , проверяется код выхода, и если он указывает, что произошла ошибка, то CalledProcessError возникает исключение.

subprocess_run_check.py

import subprocess

try:
    subprocess.run(['false'], checkTrue)
except subprocess.CalledProcessError as err:
    print('ERROR:', err)

Команда false всегда завершается с ненулевым кодом состояния, который run () интерпретирует как ошибку.

$ python3 subprocess_run_check.py

ERROR: Command '['false']' returned non-zero exit status 1

Примечание

Передача в run () делает его эквивалентным использованию check_call () .

Захват вывода

Стандартные каналы ввода и вывода для процесса, запущенного run () , привязаны к родительскому вводу и выводу. Это означает, что вызывающая программа не может захватить вывод команды. Передайте PIPE для аргументов stdout и stderr , чтобы захватить вывод для последующей обработки.

subprocess_run_output.py

import subprocess

completed  subprocess.run(
    ['ls', '-1'],
    stdoutsubprocess.PIPE,
)
print('returncode:', completed.returncode)
print('Have {} bytes in stdout:\n{}'.format(
    len(completed.stdout),
    completed.stdout.decode('utf-8'))
)

Команда ls -1 выполняется успешно, поэтому текст, который она выводит на стандартный вывод, фиксируется и возвращается.

$ python3 subprocess_run_output.py

returncode: 0
Have 522 bytes in stdout:
index.rst
interaction.py
repeater.py
signal_child.py
signal_parent.py
subprocess_check_output_error_trap_output.py
subprocess_os_system.py
subprocess_pipes.py
subprocess_popen2.py
subprocess_popen3.py
subprocess_popen4.py
subprocess_popen_read.py
subprocess_popen_write.py
subprocess_run_check.py
subprocess_run_output.py
subprocess_run_output_error.py
subprocess_run_output_error_suppress.py
subprocess_run_output_error_trap.py
subprocess_shell_variables.py
subprocess_signal_parent_shell.py
subprocess_signal_setpgrp.py

Примечание

Передача и установка для stdout значения PIPE эквивалентны использованию check_output () .

В следующем примере выполняется серия команд во вспомогательной оболочке. Сообщения отправляются на стандартный вывод и стандартную ошибку до выхода команд с кодом ошибки.

subprocess_run_output_error.py

import subprocess

try:
    completed  subprocess.run(
        'echo to stdout; echo to stderr 1>&2; exit 1',
        checkTrue,
        shellTrue,
        stdoutsubprocess.PIPE,
    )
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
else:
    print('returncode:', completed.returncode)
    print('Have {} bytes in stdout: {!r}'.format(
        len(completed.stdout),
        completed.stdout.decode('utf-8'))
    )

Сообщение стандартной ошибки выводится на консоль, но сообщение стандартного вывода скрыто.

$ python3 subprocess_run_output_error.py

to stderr
ERROR: Command 'echo to stdout; echo to stderr 1>&2; exit 1'
returned non-zero exit status 1

Чтобы сообщения об ошибках от команд, выполняемых через run () , не записывались в консоль, установите для параметра stderr константу PIPE .

subprocess_run_output_error_trap.py

import subprocess

try:
    completed  subprocess.run(
        'echo to stdout; echo to stderr 1>&2; exit 1',
        shellTrue,
        stdoutsubprocess.PIPE,
        stderrsubprocess.PIPE,
    )
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
else:
    print('returncode:', completed.returncode)
    print('Have {} bytes in stdout: {!r}'.format(
        len(completed.stdout),
        completed.stdout.decode('utf-8'))
    )
    print('Have {} bytes in stderr: {!r}'.format(
        len(completed.stderr),
        completed.stderr.decode('utf-8'))
    )

В этом примере не устанавливается , поэтому вывод команды фиксируется и печатается.

$ python3 subprocess_run_output_error_trap.py

returncode: 1
Have 10 bytes in stdout: 'to stdout\n'
Have 10 bytes in stderr: 'to stderr\n'

Чтобы записывать сообщения об ошибках при использовании check_output () , установите для stderr значение STDOUT , и сообщения будут объединены с остальной частью вывода из команда.

subprocess_check_output_error_trap_output.py

import subprocess

try:
    output  subprocess.check_output(
        'echo to stdout; echo to stderr 1>&2',
        shellTrue,
        stderrsubprocess.STDOUT,
    )
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
else:
    print('Have {} bytes in output: {!r}'.format(
        len(output),
        output.decode('utf-8'))
    )

Порядок вывода может варьироваться в зависимости от того, как буферизация применяется к стандартному потоку вывода и сколько данных печатается.

$ python3 subprocess_check_output_error_trap_output.py

Have 20 bytes in output: 'to stdout\nto stderr\n'

Подавление вывода

В случаях, когда вывод не должен отображаться или фиксироваться, используйте DEVNULL для подавления потока вывода. В этом примере подавляются как стандартный вывод, так и потоки ошибок.

subprocess_run_output_error_suppress.py

import subprocess

try:
    completed  subprocess.run(
        'echo to stdout; echo to stderr 1>&2; exit 1',
        shellTrue,
        stdoutsubprocess.DEVNULL,
        stderrsubprocess.DEVNULL,
    )
except subprocess.CalledProcessError as err:
    print('ERROR:', err)
else:
    print('returncode:', completed.returncode)
    print('stdout is {!r}'.format(completed.stdout))
    print('stderr is {!r}'.format(completed.stderr))

Имя DEVNULL происходит от файла специального устройства Unix, /dev/null , который отвечает концом файла при открытии для чтения и принимает, но игнорирует любой объем ввода. при написании.

$ python3 subprocess_run_output_error_suppress.py

returncode: 1
stdout is None
stderr is None

Непосредственная работа с трубами

Функции run () , call () , check_call () и check_output () являются оболочками вокруг Popen класс. Прямое использование Popen дает больший контроль над тем, как выполняется команда, и как обрабатываются ее входные и выходные потоки. Например, передавая разные аргументы для stdin , stdout и stderr , можно имитировать варианты os.popen ( ) .

Одностороннее общение с процессом

Чтобы запустить процесс и прочитать весь его вывод, установите для значения stdout значение PIPE и вызовите communication () .

subprocess_popen_read.py

import subprocess

print('read:')
proc  subprocess.Popen(
    ['echo', '"to stdout"'],
    stdoutsubprocess.PIPE,
)
stdout_value  proc.communicate()[0].decode('utf-8')
print('stdout:', repr(stdout_value))

Это похоже на то, как работает popen () , за исключением того, что чтение управляется внутренне экземпляром Popen .

$ python3 subprocess_popen_read.py

read:
stdout: '"to stdout"\n'

Чтобы настроить канал, позволяющий вызывающей программе записывать в него данные, установите для stdin значение PIPE .

subprocess_popen_write.py

import subprocess

print('write:')
proc  subprocess.Popen(
    ['cat', '-'],
    stdinsubprocess.PIPE,
)
proc.communicate('stdin: to stdin\n'.encode('utf-8'))

Чтобы отправить данные в стандартный входной канал процесса один раз, передайте данные в communication () . Это похоже на использование popen () с режимом 'w' .

$ python3 -u subprocess_popen_write.py

write:
stdin: to stdin

Двунаправленная коммуникация с процессом

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

subprocess_popen2.py

import subprocess

print('popen2:')

proc  subprocess.Popen(
    ['cat', '-'],
    stdinsubprocess.PIPE,
    stdoutsubprocess.PIPE,
)
msg  'through stdin to stdout'.encode('utf-8')
stdout_value  proc.communicate(msg)[0].decode('utf-8')
print('pass through:', repr(stdout_value))

Это настраивает канал для имитации popen2 () .

$ python3 -u subprocess_popen2.py

popen2:
pass through: 'through stdin to stdout'

Захват вывода ошибок

Также возможно наблюдать за обоими потоками для stdout и stderr , как и для popen3 () .

subprocess_popen3.py

import subprocess

print('popen3:')
proc  subprocess.Popen(
    'cat -; echo "to stderr" 1>&2',
    shellTrue,
    stdinsubprocess.PIPE,
    stdoutsubprocess.PIPE,
    stderrsubprocess.PIPE,
)
msg  'through stdin to stdout'.encode('utf-8')
stdout_value, stderr_value  proc.communicate(msg)
print('pass through:', repr(stdout_value.decode('utf-8')))
print('stderr      :', repr(stderr_value.decode('utf-8')))

Чтение из stderr работает так же, как с stdout . Передача PIPE указывает Popen подключиться к каналу, а communication () считывает все данные из него перед возвратом.

$ python3 -u subprocess_popen3.py

popen3:
pass through: 'through stdin to stdout'
stderr      : 'to stderr\n'

Комбинирование обычного вывода и вывода ошибок

Чтобы направить вывод ошибки из процесса в его стандартный канал вывода, используйте STDOUT для stderr вместо PIPE .

subprocess_popen4.py

import subprocess

print('popen4:')
proc  subprocess.Popen(
    'cat -; echo "to stderr" 1>&2',
    shellTrue,
    stdinsubprocess.PIPE,
    stdoutsubprocess.PIPE,
    stderrsubprocess.STDOUT,
)
msg  'through stdin to stdout\n'.encode('utf-8')
stdout_value, stderr_value  proc.communicate(msg)
print('combined output:', repr(stdout_value.decode('utf-8')))
print('stderr value   :', repr(stderr_value))

Такое объединение вывода аналогично тому, как работает popen4 () .

$ python3 -u subprocess_popen4.py

popen4:
combined output: 'through stdin to stdout\nto stderr\n'
stderr value   : None

Соединение отрезков трубы

Несколько команд можно объединить в конвейер , аналогично тому, как работает оболочка Unix, путем создания отдельных экземпляров Popen и объединения их входных и выходных данных вместе. Атрибут stdout одного экземпляра Popen используется в качестве аргумента stdin для следующего в конвейере вместо константы PIPE . Вывод считывается из дескриптора stdout для последней команды в конвейере.

subprocess_pipes.py

import subprocess

cat  subprocess.Popen(
    ['cat', 'index.rst'],
    stdoutsubprocess.PIPE,
)

grep  subprocess.Popen(
    ['grep', '.. literalinclude::'],
    stdincat.stdout,
    stdoutsubprocess.PIPE,
)

cut  subprocess.Popen(
    ['cut', '-f', '3', '-d:'],
    stdingrep.stdout,
    stdoutsubprocess.PIPE,
)

end_of_pipe  cut.stdout

print('Included files:')
for line in end_of_pipe:
    print(line.decode('utf-8').strip())

В примере воспроизводится командная строка:

$ cat index.rst | grep ".. literalinclude" | cut -f 3 -d:

Конвейер считывает исходный файл reStructuredText для этого раздела и находит все строки, содержащие другие файлы, а затем печатает имена включаемых файлов.

$ python3 -u subprocess_pipes.py

Included files:
subprocess_os_system.py
subprocess_shell_variables.py
subprocess_run_check.py
subprocess_run_output.py
subprocess_run_output_error.py
subprocess_run_output_error_trap.py
subprocess_check_output_error_trap_output.py
subprocess_run_output_error_suppress.py
subprocess_popen_read.py
subprocess_popen_write.py
subprocess_popen2.py
subprocess_popen3.py
subprocess_popen4.py
subprocess_pipes.py
repeater.py
interaction.py
signal_child.py
signal_parent.py
subprocess_signal_parent_shell.py
subprocess_signal_setpgrp.py

Взаимодействие с другой командой

Все предыдущие примеры предполагают ограниченное количество взаимодействий. Метод communications () считывает весь вывод и ожидает завершения дочернего процесса перед возвратом. Также можно записывать и считывать отдельные дескрипторы каналов, используемые экземпляром Popen , постепенно по мере выполнения программы. Простая программа эха, которая считывает со стандартного ввода и записывает в стандартный вывод, иллюстрирует эту технику.

Сценарий Repeater.py используется в качестве дочернего процесса в следующем примере. Он читает из stdin и записывает значения в stdout , по одной строке за раз, пока больше не будет ввода. Он также записывает сообщение в stderr при запуске и останове, показывая время жизни дочернего процесса.

repeater.py

import sys

sys.stderr.write('repeater.py: starting\n')
sys.stderr.flush()

while True:
    next_line  sys.stdin.readline()
    sys.stderr.flush()
    if not next_line:
        break
    sys.stdout.write(next_line)
    sys.stdout.flush()

sys.stderr.write('repeater.py: exiting\n')
sys.stderr.flush()

В следующем примере взаимодействия по-разному используются дескрипторы файлов stdin и stdout , принадлежащие экземпляру Popen . В первом примере последовательность из пяти чисел записывается в stdin процесса, и после каждой записи считывается следующая строка вывода. Во втором примере записываются те же пять чисел, но вывод считывается сразу с помощью communication () .

interaction.py

import io
import subprocess

print('One line at a time:')
proc  subprocess.Popen(
    'python3 repeater.py',
    shellTrue,
    stdinsubprocess.PIPE,
    stdoutsubprocess.PIPE,
)
stdin  io.TextIOWrapper(
    proc.stdin,
    encoding'utf-8',
    line_bufferingTrue,  # send data on newline
)
stdout  io.TextIOWrapper(
    proc.stdout,
    encoding'utf-8',
)
for i in range(5):
    line  '{}\n'.format(i)
    stdin.write(line)
    output  stdout.readline()
    print(output.rstrip())
remainder  proc.communicate()[0].decode('utf-8')
print(remainder)

print()
print('All output at once:')
proc  subprocess.Popen(
    'python3 repeater.py',
    shellTrue,
    stdinsubprocess.PIPE,
    stdoutsubprocess.PIPE,
)
stdin  io.TextIOWrapper(
    proc.stdin,
    encoding'utf-8',
)
for i in range(5):
    line  '{}\n'.format(i)
    stdin.write(line)
stdin.flush()

output  proc.communicate()[0].decode('utf-8')
print(output)

Строки "Repeater.py: exiting" находятся в разных точках вывода для каждого стиля цикла.

$ python3 -u interaction.py

One line at a time:
repeater.py: starting
0
1
2
3
4
repeater.py: exiting


All output at once:
repeater.py: starting
repeater.py: exiting
0
1
2
3
4

Сигнализация между процессами

Примеры управления процессами для модуля os включают демонстрацию передачи сигналов между процессами с помощью os.fork () и os.kill () . Поскольку каждый экземпляр Popen предоставляет атрибут pid с идентификатором дочернего процесса, можно сделать что-то подобное с subprocess . В следующем примере объединены два скрипта. Этот дочерний процесс устанавливает обработчик сигнала для сигнала USR .

signal_child.py

import os
import signal
import time
import sys

pid  os.getpid()
received  False


def signal_usr1(signum, frame):
    "Callback invoked when a signal is received"
    global received
    received  True
    print('CHILD {:>6}: Received USR1'.format(pid))
    sys.stdout.flush()


print('CHILD {:>6}: Setting up signal handler'.format(pid))
sys.stdout.flush()
signal.signal(signal.SIGUSR1, signal_usr1)
print('CHILD {:>6}: Pausing to wait for signal'.format(pid))
sys.stdout.flush()
time.sleep(3)

if not received:
    print('CHILD {:>6}: Never received signal'.format(pid))

Этот сценарий запускается как родительский процесс. Он запускает signal_child.py , затем отправляет сигнал USR1 .

signal_parent.py

import os
import signal
import subprocess
import time
import sys

proc  subprocess.Popen(['python3', 'signal_child.py'])
print('PARENT      : Pausing before sending signal...')
sys.stdout.flush()
time.sleep(1)
print('PARENT      : Signaling child')
sys.stdout.flush()
os.kill(proc.pid, signal.SIGUSR1)

Результат:

$ python3 signal_parent.py

PARENT      : Pausing before sending signal...
CHILD  26976: Setting up signal handler
CHILD  26976: Pausing to wait for signal
PARENT      : Signaling child
CHILD  26976: Received USR1

Группы процессов/сеансы

Если процесс, созданный Popen , порождает подпроцессы, эти дочерние элементы не будут получать никаких сигналов, отправленных родителю. Это означает, что при использовании аргумента shell для Popen будет трудно вызвать завершение команды, запущенной в оболочке, отправив SIGINT или SIGTERM .

subprocess_signal_parent_shell.py

import os
import signal
import subprocess
import tempfile
import time
import sys

script  '''#!/bin/sh
echo "Shell script in process $$"
set -x
python3 signal_child.py
'''
script_file  tempfile.NamedTemporaryFile('wt')
script_file.write(script)
script_file.flush()

proc  subprocess.Popen(['sh', script_file.name])
print('PARENT      : Pausing before signaling {}...'.format(
    proc.pid))
sys.stdout.flush()
time.sleep(1)
print('PARENT      : Signaling child {}'.format(proc.pid))
sys.stdout.flush()
os.kill(proc.pid, signal.SIGUSR1)
time.sleep(3)

Pid, используемый для отправки сигнала, не соответствует pid дочернего элемента сценария оболочки, ожидающего сигнала, потому что в этом примере взаимодействуют три отдельных процесса:

  1. П
  2. р
  3. о
  4. г
  5. р
  6. а
  7. м
  8. м
  9. а
  10. <
  11. c
  12. o
  13. d
  14. e
  15. >
  16. s
  17. u
  18. b
  19. p
  20. r
  21. o
  22. c
  23. e
  24. s
  25. s
  26. _
  27. s
  28. i
  29. g
  30. n
  31. a
  32. l
  33. _
  34. p
  35. a
  36. r
  37. e
  38. n
  39. t
  40. _
  41. s
  42. h
  43. e
  44. l
  45. l
  46. .
  47. p
  48. y
  49. <
  50. /
  51. c
  52. o
  53. d
  54. e
  55. >
  56. П
  57. р
  58. о
  59. ц
  60. е
  61. с
  62. с
  63. о
  64. б
  65. о
  66. л
  67. о
  68. ч
  69. к
  70. и
  71. ,
  72. з
  73. а
  74. п
  75. у
  76. с
  77. к
  78. а
  79. ю
  80. щ
  81. и
  82. й
  83. с
  84. к
  85. р
  86. и
  87. п
  88. т
  89. ,
  90. с
  91. о
  92. з
  93. д
  94. а
  95. н
  96. н
  97. ы
  98. й
  99. о
  100. с
  101. н
  102. о
  103. в
  104. н
  105. о
  106. й
  107. п
  108. р
  109. о
  110. г
  111. р
  112. а
  113. м
  114. м
  115. о
  116. й
  117. P
  118. y
  119. t
  120. h
  121. o
  122. n
  123. П
  124. р
  125. о
  126. г
  127. р
  128. а
  129. м
  130. м
  131. а
  132. <
  133. c
  134. o
  135. d
  136. e
  137. >
  138. s
  139. i
  140. g
  141. n
  142. a
  143. l
  144. _
  145. c
  146. h
  147. i
  148. l
  149. d
  150. .
  151. p
  152. y
  153. <
  154. /
  155. c
  156. o
  157. d
  158. e
  159. >
$ python3 subprocess_signal_parent_shell.py

PARENT      : Pausing before signaling 26984...
Shell script in process 26984
+ python3 signal_child.py
CHILD  26985: Setting up signal handler
CHILD  26985: Pausing to wait for signal
PARENT      : Signaling child 26984
CHILD  26985: Never received signal

Чтобы отправлять сигналы потомкам, не зная их идентификатора процесса, используйте группу процессов , чтобы связать потомков, чтобы они могли сигнализировать вместе. Группа процессов создается с помощью os.setpgrp () , который устанавливает идентификатор группы процессов равным идентификатору текущего процесса. Все дочерние процессы наследуют свою группу процессов от своего родителя, и, поскольку она должна быть установлена только в оболочке, созданной Popen и его потомками, os.setpgrp () не должен быть вызывается в том же процессе, в котором создается Popen . Вместо этого функция передается в Popen как аргумент preexec_fn , поэтому она запускается после fork () внутри нового процесса, прежде чем он использует exec () для запуска оболочки. Чтобы сигнализировать всей группе процессов, используйте os.killpg () со значением pid из экземпляра Popen .

subprocess_signal_setpgrp.py

import os
import signal
import subprocess
import tempfile
import time
import sys


def show_setting_prgrp():
    print('Calling os.setpgrp() from {}'.format(os.getpid()))
    os.setpgrp()
    print('Process group is now {}'.format(os.getpgrp()))
    sys.stdout.flush()


script  '''#!/bin/sh
echo "Shell script in process $$"
set -x
python3 signal_child.py
'''
script_file  tempfile.NamedTemporaryFile('wt')
script_file.write(script)
script_file.flush()

proc  subprocess.Popen(
    ['sh', script_file.name],
    preexec_fnshow_setting_prgrp,
)
print('PARENT      : Pausing before signaling {}...'.format(
    proc.pid))
sys.stdout.flush()
time.sleep(1)
print('PARENT      : Signaling process group {}'.format(
    proc.pid))
sys.stdout.flush()
os.killpg(proc.pid, signal.SIGUSR1)
time.sleep(3)

Последовательность событий такова.

  1. Р
  2. о
  3. д
  4. и
  5. т
  6. е
  7. л
  8. ь
  9. с
  10. к
  11. а
  12. я
  13. п
  14. р
  15. о
  16. г
  17. р
  18. а
  19. м
  20. м
  21. а
  22. с
  23. о
  24. з
  25. д
  26. а
  27. е
  28. т
  29. э
  30. к
  31. з
  32. е
  33. м
  34. п
  35. л
  36. я
  37. р
  38. <
  39. c
  40. o
  41. d
  42. e
  43. >
  44. P
  45. o
  46. p
  47. e
  48. n
  49. <
  50. /
  51. c
  52. o
  53. d
  54. e
  55. >
  56. .
  57. Э
  58. к
  59. з
  60. е
  61. м
  62. п
  63. л
  64. я
  65. р
  66. <
  67. c
  68. o
  69. d
  70. e
  71. >
  72. P
  73. o
  74. p
  75. e
  76. n
  77. <
  78. /
  79. c
  80. o
  81. d
  82. e
  83. >
  84. в
  85. ы
  86. з
  87. ы
  88. в
  89. а
  90. е
  91. т
  92. н
  93. о
  94. в
  95. ы
  96. й
  97. п
  98. р
  99. о
  100. ц
  101. е
  102. с
  103. с
  104. .
  105. Н
  106. о
  107. в
  108. ы
  109. й
  110. п
  111. р
  112. о
  113. ц
  114. е
  115. с
  116. с
  117. з
  118. а
  119. п
  120. у
  121. с
  122. к
  123. а
  124. е
  125. т
  126. <
  127. c
  128. o
  129. d
  130. e
  131. >
  132. o
  133. s
  134. .
  135. s
  136. e
  137. t
  138. p
  139. g
  140. r
  141. p
  142. (
  143. )
  144. <
  145. /
  146. c
  147. o
  148. d
  149. e
  150. >
  151. .
  152. Н
  153. о
  154. в
  155. ы
  156. й
  157. п
  158. р
  159. о
  160. ц
  161. е
  162. с
  163. с
  164. з
  165. а
  166. п
  167. у
  168. с
  169. к
  170. а
  171. е
  172. т
  173. <
  174. c
  175. o
  176. d
  177. e
  178. >
  179. e
  180. x
  181. e
  182. c
  183. (
  184. )
  185. <
  186. /
  187. c
  188. o
  189. d
  190. e
  191. >
  192. д
  193. л
  194. я
  195. з
  196. а
  197. п
  198. у
  199. с
  200. к
  201. а
  202. о
  203. б
  204. о
  205. л
  206. о
  207. ч
  208. к
  209. и
  210. .
  211. О
  212. б
  213. о
  214. л
  215. о
  216. ч
  217. к
  218. а
  219. з
  220. а
  221. п
  222. у
  223. с
  224. к
  225. а
  226. е
  227. т
  228. с
  229. ц
  230. е
  231. н
  232. а
  233. р
  234. и
  235. й
  236. о
  237. б
  238. о
  239. л
  240. о
  241. ч
  242. к
  243. и
  244. .
  245. С
  246. ц
  247. е
  248. н
  249. а
  250. р
  251. и
  252. й
  253. о
  254. б
  255. о
  256. л
  257. о
  258. ч
  259. к
  260. и
  261. с
  262. н
  263. о
  264. в
  265. а
  266. р
  267. а
  268. з
  269. в
  270. е
  271. т
  272. в
  273. л
  274. я
  275. е
  276. т
  277. с
  278. я
  279. ,
  280. и
  281. э
  282. т
  283. о
  284. т
  285. п
  286. р
  287. о
  288. ц
  289. е
  290. с
  291. с
  292. з
  293. а
  294. п
  295. у
  296. с
  297. к
  298. а
  299. е
  300. т
  301. P
  302. y
  303. t
  304. h
  305. o
  306. n
  307. .
  308. P
  309. y
  310. t
  311. h
  312. o
  313. n
  314. з
  315. а
  316. п
  317. у
  318. с
  319. к
  320. а
  321. е
  322. т
  323. <
  324. c
  325. o
  326. d
  327. e
  328. >
  329. s
  330. i
  331. g
  332. n
  333. a
  334. l
  335. _
  336. c
  337. h
  338. i
  339. l
  340. d
  341. .
  342. p
  343. y
  344. <
  345. /
  346. c
  347. o
  348. d
  349. e
  350. >
  351. .
  352. Р
  353. о
  354. д
  355. и
  356. т
  357. е
  358. л
  359. ь
  360. с
  361. к
  362. а
  363. я
  364. п
  365. р
  366. о
  367. г
  368. р
  369. а
  370. м
  371. м
  372. а
  373. с
  374. и
  375. г
  376. н
  377. а
  378. л
  379. и
  380. з
  381. и
  382. р
  383. у
  384. е
  385. т
  386. г
  387. р
  388. у
  389. п
  390. п
  391. е
  392. п
  393. р
  394. о
  395. ц
  396. е
  397. с
  398. с
  399. о
  400. в
  401. ,
  402. и
  403. с
  404. п
  405. о
  406. л
  407. ь
  408. з
  409. у
  410. я
  411. p
  412. i
  413. d
  414. о
  415. б
  416. о
  417. л
  418. о
  419. ч
  420. к
  421. и
  422. .
  423. С
  424. и
  425. г
  426. н
  427. а
  428. л
  429. п
  430. о
  431. л
  432. у
  433. ч
  434. а
  435. ю
  436. т
  437. п
  438. р
  439. о
  440. ц
  441. е
  442. с
  443. с
  444. ы
  445. о
  446. б
  447. о
  448. л
  449. о
  450. ч
  451. к
  452. и
  453. и
  454. P
  455. y
  456. t
  457. h
  458. o
  459. n
  460. .
  461. О
  462. б
  463. о
  464. л
  465. о
  466. ч
  467. к
  468. а
  469. и
  470. г
  471. н
  472. о
  473. р
  474. и
  475. р
  476. у
  477. е
  478. т
  479. с
  480. и
  481. г
  482. н
  483. а
  484. л
  485. .
  486. П
  487. р
  488. о
  489. ц
  490. е
  491. с
  492. с
  493. P
  494. y
  495. t
  496. h
  497. o
  498. n
  499. ,
  500. в
  501. ы
  502. п
  503. о
  504. л
  505. н
  506. я
  507. ю
  508. щ
  509. и
  510. й
  511. <
  512. c
  513. o
  514. d
  515. e
  516. >
  517. s
  518. i
  519. g
  520. n
  521. a
  522. l
  523. _
  524. c
  525. h
  526. i
  527. l
  528. d
  529. .
  530. p
  531. y
  532. <
  533. /
  534. c
  535. o
  536. d
  537. e
  538. >
  539. ,
  540. в
  541. ы
  542. з
  543. ы
  544. в
  545. а
  546. е
  547. т
  548. о
  549. б
  550. р
  551. а
  552. б
  553. о
  554. т
  555. ч
  556. и
  557. к
  558. с
  559. и
  560. г
  561. н
  562. а
  563. л
  564. а
  565. .
$ python3 subprocess_signal_setpgrp.py

Calling os.setpgrp() from 75636
Process group is now 75636
PARENT      : Pausing before signaling 75636...
Shell script in process 75636
+ python3 signal_child.py
CHILD  75637: Setting up signal handler
CHILD  75637: Pausing to wait for signal
PARENT      : Signaling process group 75636
CHILD  75637: Received USR1

Смотрите также