Python: запуск файла bach и чтение выходных данных до появления определенной строки и продолжения

#python #subprocess

#python #подпроцесс

Вопрос:

Итак, у меня есть batch файл, который запускает appium сервер.

Когда я начинаю выполнять свой batch файл, я хочу прочитать выходные данные, а при server запуске я хочу продолжить.

Я знаю, когда appium сервер запускается с этого вывода:

 Appium REST http interface listener started on 0.0.0.0:4723
  

В настоящее время это то, что у меня есть:

 process = subprocess.Popen([r'C:\appium.bat'])
stdout = process.communicate()[0]
print('STDOUT:{}'.format(stdout))
  

Я хочу подождать до 60 нескольких секунд или пока не появится эта строка.
В случае 60 , если secods проходят, а эта строка ( Appium REST http interface listener started on 0.0.0.0:4723 ) не появилась, я хочу поднять exception .

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

Есть предложения, как это решить?

Ответ №1:

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

 import time
import subprocess
import re


proc = subprocess.Popen(['/tmp/test.sh'], stdout=subprocess.PIPE)

timeout = time.time()   10 # adjust the timeout value here
target = ".*started on .*"

while True:
    if time.time() >= timeout:
        raise Exception("Server wasn't started")
    else:
        output = proc.stdout.readline()
        # read a line of input

        if output == '' and proc.poll() is not None:
            # process is not running anymore, 
            # proc.poll() will return None if process is still running
            raise Exception("Server process has stopped")
        else:
            line = output.decode().strip()
            if re.match(target, line):
                # if the pattern is matched, do something and break
                print("Server has started")
                break
            time.sleep(0.5)
  

Это файл bash, который я использовал для тестирования. Сохраните его как /tmp/test.sh

 #!/bin/bash

echo "TEST"
sleep 1
echo "server has started on 0.0.0.0"
  

Комментарии:

1. Я пытаюсь изменить цель на то, что будет отсутствовать, и код не вызывает исключения

2. @falukky вы хотите вызывать исключение только по истечении времени ожидания, верно? Я думаю target , что шаблон, который вы используете, соответствует. Можете ли вы сказать мне значение target шаблона и фактическую строку, которую вы пытаетесь сопоставить?

3. @falukky вы можете просто попробовать прокомментировать оператор echo в test.sh . Это вызовет исключение, поскольку target шаблон не может быть сопоставлен

Ответ №2:

Вы можете подождать, используя модуль time

 import time

time.sleep(60) # wait for 60 seconds
  

Комментарии:

1. Но как я могу выйти, когда получу нужную строку? я не могу убить процесс appium, потому что я хочу его использовать

Ответ №3:

Вы могли бы сделать это с помощью signal.alarm ,

 import signal
import time
import subprocess

def handler(signum, stack):
    raise Exception("It didn't happen in time...") # raise exception if it didn't come up within the time frame 

signal.signal(signal.SIGALRM, handler)
signal.alarm(60)
process = subprocess.Popen([r'C:\appium.bat'])
stdout = process.communicate()[0] # assuming this blocks
print('STDOUT:{}'.format(stdout))
signal.alarm(0) # turn of the alarm, if it came up within 60 seconds
  

если .communicate() нет blocking , то,

 import subprocess
process = subprocess.Popen([r'C:\appium.bat'])
stdout = process.communicate()[0] # non blocking ?
print('STDOUT:{}'.format(stdout))
time.sleep(60)
if 'Appium REST http interface listener started' not in stdout:
    raise Exception("It didn't come up in time...")
  

Комментарии:

1. Я немного смущен, где именно мне нужно использовать этот код и как?

2. @falukky Я предполагаю .communicate() , что он будет блокироваться до тех REST API пор, пока не появится?

3. В настоящее время мой код печатает выходные данные процесса, и поскольку процесс, выполняющий его, никогда не продолжается, и вы завершаете работу в этой строке: signal.signal(сигнал. SIGALRM, обработчик)

4. О чем это говорит crash ?

5. Ошибка атрибута: модуль ‘signal’ не имеет атрибута ‘SIGALRM’