подпроцесс: запустить процесс в фоновом режиме и запустить другой одним вызовом

Эта программа должна немедленно вывести pid сна:

import subprocess
subprocess.check_output("sleep 1 & echo $!", shell=True)

Запустив это непосредственно в оболочке, он сразу же распечатает pid, но запустив его в python, & игнорируется, и до выполнения echo требуется 1 секунда.

Как я могу заставить это работать только с одним выполнением check_output (или другой функцией subprocess)?

(Это упрощенный пример, в реальности вместо sleep 1 я бы поставил свой экзешник)


person hansaplast    schedule 02.05.2017    source источник


Ответы (1)


check_output ждет закрытия выходных каналов, и sleep тоже их имеет. Вы можете перенаправить на /dev/null для немедленного возврата.

subprocess.check_output("sleep 1 >/dev/null 2>&1 & echo $!", shell=True)

ОБНОВИТЬ

Трудно сказать, действительно ли sleep 1 работал в фоновом режиме, поэтому я написал немного больший тест.

test.py — записывает время в stdout в течение 5 секунд

import time

for i in range(5):
    print(time.strftime('%H:%M:%S'), flush=True)
    time.sleep(1)
print('done', flush=True)

runner.py — запускает тест, перенаправляя stdout в файл, и отслеживает файл.

import subprocess as subp
import time
import os

# run program in background
pid = int(subp.check_output("python3 test.py >test.out 2>&1 & echo $!",
    shell=True))
print("pid", pid)

# monitor output file
pos = 0
done = False
while not done:
    time.sleep(.1)
    if os.stat('test.out').st_size > pos:
        with open('test.out', 'rb') as fp:
            fp.seek(pos)
            for line in fp.readlines():
                print(line.strip().decode())
                done = b'done' in line
            pos = fp.tell()
print("test complete")

Запустив его, я получаю

td@mintyfresh ~/tmp $ python3 runner.py
pid 24353
09:32:18
09:32:19
09:32:20
09:32:21
09:32:22
done
test complete
person tdelaney    schedule 02.05.2017
comment
Ага, поэтому и блокирует. Это странно, потому что я думал, что python просто отправляет команду целиком в оболочку и подключается к выходным каналам оболочки. Теперь я хочу отправить несколько сигналов моей программе во время ее работы с перенаправлением всех выходных каналов, сон немедленно останавливается и не работает в фоновом режиме. Могу ли я как-то этого добиться? - person hansaplast; 02.05.2017
comment
sleep выполнялся до завершения в фоновом режиме - просто спящую 1 секунду довольно трудно обнаружить. Сделайте 60 секунд и запустите ps, вы это увидите. Вы можете перенаправить на другие файлы, если хотите сохранить вывод, а поскольку check_output возвращает pid, у вас есть механизм для отправки сигналов. - person tdelaney; 02.05.2017
comment
спасибо, что нашли время написать сценарий. Это действительно показывает, что это работает. Я застрял с отправкой SIGINT в процесс, который я только что начал (вероятно, из-за идентификаторов группы процессов), но я могу открыть другой вопрос для этой проблемы. - person hansaplast; 03.05.2017