запуск программы при изменении выходных данных команды в bash

#bash

Вопрос:

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

foo пример:

 while true; do  echo hi  sleep 1 done  

я не могу редактировать foo

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

1. Можете ли вы уточнить, что вы подразумеваете под «новой строкой»? Возможно, это хорошая возможность для более длинного сценария оболочки, использующего цикл while. Интересно, могли бы вы сделать однострочную прокладку, используя watch и diff и множество операторов труб.

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

3. Используйте read встроенное, см. help read

Ответ №1:

Вот функция, которая, я думаю, послужит вашей цели:

 function my_function { while true; do read amp;amp; "$@" ; done ; }  

Чтобы запускать программу prog каждый раз, когда программа foo выводит строку, вы можете написать это на терминале:

 foo | my_function prog  

Если вы хотите передать arg1 и arg2 в качестве аргументов «прогу», вы можете назвать это так (спасибо @Ульрих Экхардт и @Гленн Джекман):

 foo | my_function prog arg1 arg2  

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

1. куда мне позвонить фу?

2. foo | my_function "echo hello" — вы передаете вывод foo в программу, реагирующую на его вывод.

3. Я бы предложил: my_function() { while true; do read amp;amp; "$@"; done; } тогда вы можете отправлять любые произвольные аргументы, даже содержащие пробелы: foo | my_function prog "arg the first" "arg the second"

4. Как предложил @glennjackman, пожалуйста, отредактируйте свой ответ и замените $@ на "$@" , иначе я понижу ваш голос 😛

5. Да, всегда цитируйте "$@" , если только вы точно не знаете, что произойдет, если вы этого не сделаете.

Ответ №2:

Как уже предлагалось в комментариях, вы можете использовать while read для выполнения итерации цикла для каждой строки вывода foo .

 foo | while IFS= read -r line; do  # maybe echo "$line"?  echo "hi" done  

Существуют опции read , позволяющие использовать разделитель ввода, отличный от новой строки.

Это можно было бы значительно упростить, если бы вы действительно заботились только о том, чтобы что-то делать, когда приходит строка, но не о фактическом выводе перед новой строкой. -r Опция и IFS= назначение помогают сохранить точное содержимое line внутри цикла (в частности, IFS= не позволяет оболочке удалять пробелы из входного значения, а -r опция отключает синтаксический анализ обратных косых черт, чего вы обычно не хотите).