Как реагировать на стандартный ввод и печатать на стандартный вывод одновременно? - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть сценарий bash, который выполняется вечно и печатает некоторую информацию с различными интервалами. Для простоты; предположим, что это мой bash скрипт; давайте назовем это mybashscript.sh

#!/bin/bash
while :
do
    echo "The loop has printed"
    sleep 5
done

Это просто из соображений простоты; Мой настоящий сценарий не так прост. (У меня есть около 30 из этих не разветвленных, не запускаемых в оболочку bash сценариев.)

Я хочу написать python программу, которая будет;

  • Запустить это bash script
  • Получить вывод из stdout сценария bash; и проанализировать его (для простоты; скажем, я хочу добавить строку [python] в начале каждой строки) и распечатать его.
  • Завершит работу сценария bash, когда сценарий python прекращается.
  • В то же время; ответить на строки в python stdin (для простоты; допустим, я хочу пропустить песню, когда есть ввод с клавиатуры на stdin.

У меня есть следующая программа для этого; давайте назовите это mywrapper.py (я использую здесь команду mpc next; потому что мне довольно легко понять, вызвано ли это; у меня включены наушники)

#!/bin/env python
import os
import re
import sys
import threading
import subprocess

def response():
    """ Just one function to check if functions work """
    subprocess.call(['mpc', 'next'],
                    stdin=subprocess.DEVNULL,
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL)

def listen(inp):
    """ Respond to stdin """
    for line in inp:
        response()

if __name__ == '__main__':
    # Test the response function
    response()
    # Start the infinite loop
    SCRIPT = subprocess.Popen('/tmp/mybashscript.sh',
                              stdin=subprocess.DEVNULL,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.DEVNULL)
    # Start the listener
    LISTEN = threading.Thread(target=listen,
                              args=(sys.stdin))
    LISTEN.start()
    # Respond to lines in the script
    while True:
        LINE = SCRIPT.stdout.readline()
        # If the script terminated; get out of loop to terminate program
        if not LINE:
           break

        print('[python]' + str(LINE))
        # Need this to stop buffering
        sys.stdout.flush()

Однако; listen ничего не делать. Функция ответа работает нормально; при первом вызове. Как я могу изменить мой python сценарий для ответа на ввод?

Кроме того, для остановки этой программы требуется два прерывания клавиатуры. Как я могу скажите, будет ли SIGTERM убивать также все дочерние процессы?

Чтобы избежать проблемы XY, вот именно то, что я пытаюсь сделать;

  • Я пытаюсь написать программу, которая будет взаимодействовать с другой программой. Я нахожусь на Linux, и я хочу использовать i3blocks для отображения информации на моем экране, когда я использую i3 / sway.
  • Я хочу используйте опцию постоянства, которая изменит Текст, который i3blocks отображает только тогда, когда связанный скрипт печатает новую строку.
  • У меня есть скрипт da sh, называемый music, который печатает имя текущей воспроизводимой песни, и печатает новую строку только при изменении песни. Сюда; мне не нужно опрашивать информацию и не нужно постоянно обновлять текст, если я не играю какие-либо песни.
  • Я написал оболочку python, которая называется sysinfo-i3bar; в основном форматирование вывода строки так, чтобы оно было в формате json; как я могу контролировать цвета и прочее. (Причина, по которой я не выполняю полный json синтаксический анализ сценария da sh, заключается в том, что я хочу повторно использовать исходный сценарий; но в других программах, таких как polybar ; наличие одного информационного сценария и тогда полезно иметь несколько оберток для нескольких случаев) Пока все хорошо.
  • Если я нажму на экранный блок на i3blocks; символ в зависимости от нажатой кнопки, например, 1 для щелчка левой кнопкой мыши или 2 для щелчка правой кнопкой мыши, отправляется на стандартный ввод запущенного сценария. То, что я хочу сделать, это ответить на эти события; и, например, запустить mpc toggle, когда область будет нажата. Я не могу понять, как это сделать в настоящее время.
  • Я пытаюсь ответить на stdin в оболочке; а не оригинальный скрипт da sh, потому что другие строки состояния не работают так. (Polybar просто нужен собственный синтаксис, обернутый вокруг текста для выполнения команды при щелчках, как это видно в моей оболочке sysinfo-polybar.)

В конце концов; Я хотел бы упаковать эти сценарии / оболочки и выпустить его для сообщества. Я ценю любую помощь.

...