LINUX.ORG.RU

Как иницииорвать запуск при появлении вывода

 


1

2

При выполнении программы в вывод не поступает никаких данных до достижения определённых условий. Как инициировать запуск второй программы при появлении какого-либо вывода от первой? Вывод первой программы всегда разный. Вторая программа должна запуститься один раз, либо с фиксированной зедержкой, так как первая программа может выводить слишком много. Возможно поможет xargs, но я не совсем понимаю как он работает, возможно должно получится что-то похожее на это: ./script.sh | xargs -?? ./detect.sh

Во-первых, для определения того, что произошёл вывод, используй функцию select(1, {0}, NULL, NULL, NULL) справа от пайпа (слева - программа, которая выводит) и затем execve() то, что надо запустить.

Во-вторых, тут может быть проблема. Этот самый ./script.sh, обнаружив что работает не в интерактивной консоли, может начать буферизовать вывод и не сразу слать его дальше. Но тут уже зависит от конкретных деталей.

firkax ★★★★★
()
Ответ на: комментарий от vachicul

Синтаксис непонятен. Как это правильно дописать справа?

https://www.freebsd.org/cgi/man.cgi?select

Это не «справа», это надо в файл писать и потом компилировать. И свою прогу уже вызываешь справа.

Что значит не в интерактивной консоли?

Интерактивная консоль - когда прога выводит что-то сразу в терминал. А тут редирект в другую прогу.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Компилировать невариант. Нужен простой путь. Возможно через цикл проверять на наличие данных - if/then? Какие детали нужны что бы узнать буферизирует ли? Нашёл то что флаг -n означает если строка не пуста.

var=$(./script.sh)
while true; do
if [ -n = $var ]; then
./detect.sh
done

Как правильно писать не знаю, но идея верная?

vachicul
() автор топика
Ответ на: комментарий от anonymous

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

vachicul
() автор топика
Ответ на: комментарий от vachicul

И какие проблемы? Подсказку я дал, как сделать ожидание. Точное решение не дам, я вредный.

anonymous
()
Ответ на: комментарий от anonymous

Спасибо за подсказку, но это не решило мою проблему.

vachicul
() автор топика

Допустим, у нас есть некий файл:

touch testfile.txt

Запускаем мониторинг в консоли:

tail -f testfile.txt | while read -r line; do echo "Передаём строку: $line в другую программу" | cat; break; done

Консоль заблокируется и будет в ожидании. Теперь запишем что нибудь в файл testfile.txt:

echo "Hello World!" >> testfile.txt

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

dva20
()
Ответ на: комментарий от dva20

Непонятная логика. При чём здесь cat? Программу №2 нужно запускать только в том случае, если есть какой-то вывод из программы №1, значения вывода передавать другой программе не нужно.

vachicul
() автор топика
Ответ на: комментарий от vachicul

При чём здесь cat?

Это был пример «Программы №2».

значения вывода передавать другой программе не нужно

Ну и не передавай, никто не заставляет.

dva20
()
Ответ на: комментарий от dva20

Не сработало для меня. Или я не понял куда нужно подставить программу №2

vachicul
() автор топика
Ответ на: комментарий от dva20

Я так и понял что это пример. Тогда просто вместо этого echo "Передаём строку: $line в другую программу" подставить программу №2 ? break означает закончить цикл?

vachicul
() автор топика
Ответ на: комментарий от vachicul

Программу №2 нужно запускать только в том случае, если есть какой-то вывод из программы №1, значения вывода передавать другой программе не нужно

OUT=`prog1`
if [ -n "$OUT" ] ; then
  prog2
fi
gremlin_the_red ★★★★★
()
Последнее исправление: gremlin_the_red (всего исправлений: 1)
Ответ на: комментарий от gremlin_the_red

Программа №2 выполняется сразу, не дождавшись вывода №1, более того, №1 даже не запускается.

vachicul
() автор топика
Ответ на: комментарий от gremlin_the_red

Чем отличается out=`prog1```` отout=$(prog1)``` ?

Поставил бувы те что на букве ё, теперь программа №1 запускается но №2 не хочет, хотя вывод из №1 есть.

vachicul
() автор топика

Просто создай именованный канал и пусть один в него пишет, другой читает - читать он не сможет пока другой не начнёт в него писать.

AKonia ★★★
()
Ответ на: комментарий от vachicul

Может быть дело в том что if запускается однократно? Программа №1 работает постоянно и при возникновении условий даёт вывод. Может if нужно обернуть в while?

vachicul
() автор топика
Ответ на: комментарий от vachicul
mkfifo my_pipe
# 1-ый терминал
./отработать_по_появлении_ввода.sh < my_pipe
# 2-ый терминал
./выдать_вывод.sh > my_pipe

# Более примитивный пример, 1-ый терминал
cat < my_pipe
# 2-ой
echo "Hello" > my_pipe
AKonia ★★★
()
Последнее исправление: AKonia (всего исправлений: 2)
Ответ на: комментарий от AKonia

Еле разобрался. Но «echo helo > pipe» создаст пустой файл pipe сразу, не дожидаясь вывода. После вывода данных он заново не создаётся.

vachicul
() автор топика
Ответ на: комментарий от vachicul

А вы чего хотели ? Эхо в результате вывода запишет и конец файла и закроет канал, а соответственно котяра тоже закончит чтение и работу. Если ваш вывод не будет содержать конца файла, то чтение будет длиться сколь угодно долго, как пример наберите на втором конце cat > my_pipe и соответственно сможете наблюдать, как каждая введённая вами строка выводится на приёмнике. В остальном никто не запрещает в цикле это делать, грубовато, но вполне должно сработать. В целом если ваша цель выполнить чтение в программу с другой программы, у которой ожидается вывод, то это вполне делается на каналах, с другой стороны, если вы прям хотите именно начать соединение к моменту появления вывода, то тогда это полагаю стандартных консольных средств для этого нет, т.к. большинство из них расчитаны на функционирование, а не ожидание, как вариант можете просто погружать сценарий в сон на какое-нибудь время, а по пробуждению читать очередную порцию из канала

AKonia ★★★
()
Последнее исправление: AKonia (всего исправлений: 4)
Ответ на: комментарий от AKonia

Понятно что ничего непонятно. Покажите на примере prog1 и prog2. В вашем примере, после того как prog2 выводит что-либо, prog1 не реагирует потому что my_pipe не перезаписывается по мере вывода prog1.

vachicul
() автор топика
Ответ на: комментарий от dva20

Этот вариант сработал, НО не сразу, а где-то через секунд 10, при этом программа №1 должна выводить для этого без остановки. Если выведет чуть-чуть, то while не воспринимает или не успевает. Странное поведение.

vachicul
() автор топика
Ответ на: комментарий от vachicul

В каком смысле ? В моём самом втором(примитивном) примере мы предварительно создаём канал mkfifo my_pipe

# Запускаем cat, который будет ждать ввода с канала
cat < my_pipe

# В другом терминале выполняем 
echo "Hello" > my_pipe
# В результате чего в канал будет записано
# Hello и затем закрыт канал
# на первой консоли, как по появлении в канале данных
# считает их, выведет Hello и встретив конец файла, также закончит чтение
AKonia ★★★
()
Ответ на: комментарий от AKonia

Канал закрывается сразу после запуска программы №1 ./prog1 > my_pipe Но prog1 ничего не выводила, условия для вывода не достигнуты. Почему закрылся канал?

vachicul
() автор топика
Ответ на: комментарий от AKonia

awk тоже может проверять условия. Может такую конструкцию сделать? ./prog1 | awk '{ if (-n $1) exec ./prog2 }' В написании ошибаюсь явно, но принцп должен быть понятен.

vachicul
() автор топика
Ответ на: комментарий от vachicul

Первой должна включаться в работу читающая(ожидающая) из канала программа, потому что в противном случае пишущая будет писать в никуда.

AKonia ★★★
()
Ответ на: комментарий от vachicul

Всё зависит от задачи, если вам достаточно последовательного выполнения, то можно было и так:

./writer > file.txt && ./reader < file.txt

Если всё же вы хотите общения программ, то как сказал можно применить каналы.

AKonia ★★★
()
Последнее исправление: AKonia (всего исправлений: 1)
Ответ на: комментарий от AKonia

Как это будет работать? && - будет ждать завершения writer но он не завершится потому что работает без остановки. Та же ситуация, file.txt появляется, но он пустой и при выводе программы №1 он не перезаписывается.

Для меня сработал этот сценарий, но prog2 выполняется не сразу, а только если вывод из prog1 будет выходить какое-то время. То есть эта конструкция не работает мгновенно, а с задержкой. ./prog1 | while read str; do if [ -n $1 ]; then ./prog2; fi; break; done Почему задержка?

vachicul
() автор топика
Ответ на: комментарий от vachicul

опечатался

Нет. Ты или копируй, как есть, или не пиши вообще. И так много чего насочинял несоответствующее действительности.

anonymous
()
Ответ на: комментарий от anonymous

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

./prog1 | while read str; do if [ -n $str ]; then ./prog2; fi; break; done
Это работает, но не мгновенно. prog1 приходится выводить данные 7 секунд прежде чем сработает prog2. А если prog1 перестаёт выводить раньше времени, то условие [-n $str] не срабатывает и prog2 не запускается. Почему?

vachicul
() автор топика
Ответ на: комментарий от vachicul

read line - читает целую строку, пока не встретится ‘\n’. prog1 выводит строки или условный мусор?

[ -n $str ] - неправильно: или [ -n "$str" ] или [[ -n $str ]]

зачем тебе цикл while, если только один раз надо запустить?

Уже подсказывал read -n1. Почитай уже ман баша про read

anonymous
()
Ответ на: комментарий от anonymous

На примере простой программы, условие срабатывает мгновенно и prog2 запускается. В этом примере while read ждёт какое-то содержимое в файле file, как только содержимое появляется, prog2 выполняется.

 while true; do cat file; done 2>/dev/null | while read str; do if [ -n $str ]; then ./prog2; fi; break; done 
Но в случае с моей программой это не работает.. Почему?)

[ -n $str ] - неправильно: или [ -n «$str» ] или [[ -n $str ]]

уменьшило время срабатывания до 4 секунд.

read line - читает целую строку, пока не встретится ‘\n’.

с таким вариантом время срабатывания 7-10 секунд

зачем тебе цикл while, если только один раз надо запустить? Уже >подсказывал read -n1. Почитай уже ман баша про read

Куда этот read -n1 нужно пропихнуть?

 ./prog1 | read -n1 
??

не могу найти ман на русском.

vachicul
() автор топика
Ответ на: комментарий от anonymous

prog1 выводит строки или условный мусор?

выводит строки

./prog1
384957023.84,
9734980.4534,
32545532.545,

vachicul
() автор топика
Ответ на: комментарий от vachicul

Пиши в job, может кто поможет, но не я.

anonymous
()

Короче последний пример.

  1. Создаёшь в папке именованый канал
mkfifo my_pipe
  1. В этой же папке например создаёшь сценарий writer.sh
for i in 1 2 3 4
do
    sleep 1
    echo $((1 + $RANDOM % 10))
done

и сценарий reader.sh:

while read line
do
    echo $line
done
  1. В одном терминале запускаем reader.sh
bash ./reader.sh < my_pipe
  1. В другом терминале запускаем сценарий writer.sh
bash ./writer.sh > my_pipe

В качестве результата наблюдаем примерно то, что вы и заказывали - читатель запускается и виснет в ожидании ввода писателя и как только поступает ввод, она его шаг за шагом читает и так сколько угодно долго. Если это не то что ты спрашиваешь, то рекомендую тебе прежде всего научится изъяснять свои мысли, т.к. судя по вопросу - это то, но если это то и ты не смог заставить работать готовое решение, то тут я ничем помочь увы не могу. Своё доделываешь по аналогии.

AKonia ★★★
()
Последнее исправление: AKonia (всего исправлений: 4)
Ответ на: комментарий от AKonia

Этот вариант тоже работает, но снова же, реакция не мгновенная. prog1 нужно выводить 10 секунд прежде чем вывод запишется в pipe. Я изначально всё правильно объяснил. Ваши варианты работают, но не так быстро как хотелось бы.

vachicul
() автор топика
Ответ на: комментарий от AKonia

Так уже, вроде

prog1 нужно выводить 10 секунд прежде чем вывод запишется в pipe.

Подозреваю тут еще stdbuf надо использовать

anonymous
()
Ответ на: комментарий от anonymous

В prog1 добавил stdbuf -oL и всё мгновенно заработало.Только я использовал эту конструкцию

./prog1 | while read str; do if [ -n $str ]; then ./prog2; fi; break; done

Вы говорили можно обойтись без whilе с помощью read -n1. Куда его приткнуть?!

vachicul
() автор топика
Ответ на: комментарий от vachicul

Зачем while? Тем более если break; done? Ты понимаешь, вообще, что пишешь?

А бы тебе помог, если бы ты показал, что понимаешь, что пишешь. Но нет, ты упорно генерируешь непонятную хрень.

anonymous
()
Ответ на: комментарий от vachicul

prog1 нужно выводить 10 секунд прежде чем вывод запишется в

Если вывод буферизируется или вы делаете сложные вычисления или сами где-то устанавливаете дополнительные sleep… то это вполне логично полагаю что будет иметь место задержка.

AKonia ★★★
()
Ответ на: комментарий от anonymous

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

vachicul
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.