Давай повелосипедим и напишем таймер на со-процессах, без использования каких-то внешних команд типа sleep и т.п.

#!/bin/bash

coproc read
read -t 0.10 -u "${COPROC[0]}"
echo 'new velosiped'
read -t 11 -u "${COPROC[0]}"
exit
  1. Создаем фоновый со-процесс read
  2. Спим 0.10 секунды
  3. Выводим на экран new velosiped
  4. Опять спим, но уже 11 секунд
  5. Выходим

За указания задержки, как раз отвечает параметр -t. А параметр -u говорит что чтение данных нужно осуществлять с файлового дескриптора запущенного в фоне со-процесса. Белиберда? Еще какая!

В sleep, кстати тоже можно указывать миллисекунды: sleep 0.10

Со-процессинг это одновременное выполнение двух процедур, одна из которых считывает вывод другой.

Чтобы запустить со-процесс, используется зарезервированное слово coproc. Доступ к этому со-процессу осуществляется посредством массива COPROC.

${COPROC[0]} - для чтения ${COPROC[1]} - для записи

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

Если запустить одну команду coproc read, на экран выведется PID запущенного в фоне процесса [1] 126594. Чтобы посмотреть список запущенных в фоне команд, выполняем jobs и видим список:

[1] Running coproc COPROC read &
[2] Running coproc COPROC read &
[3] Running coproc COPROC read &

То есть получается ты запускаешь в фоне какую-то программу, а в другой программе, подключаешься через массив COPROC записываешь либо считываешь нужные тебе данные.

Еще пример:

coproc awk '{print $2;fflush();}'
echo bom bim bom >&${COPROC[1]}
read -ru ${COPROC[0]} var
echo $var

По итогу получаем вывод на экран, слово: bim

Давай попробуем попроще:

coproc (echo $(whoami))
read -r user <&"${COPROC[0]}"
echo $user
  1. Создаем со-процесс, который в фоне выполнит whoami
  2. Прочитаем в переменную user, то что вывел со-процесс
  3. Выводим на экран, у меня отобразилось root

Фуф, тут вроде более понятно получилось объяснить. Ну а если не понял, значит оно нахер тебе и не нужно.

Короче без бутылки тут не разобраться, это из оперы «высший пилотаж» и брейнфак.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Зачем это нужно и где применять? Понятия не имею. Я обычно не лезу в со-процессы, это усложняет скрипт, а коллеги которые не в теме, вообще не смогут его поддерживать.

Ну и на закуску, совсем уж упороться:

Несколько команд, которые помогут понять, как вся эта шляпа реализована.

coproc read
echo "${COPROC[@]}"
ls -l /proc/$$/fd | grep 'pipe'
ls -l /proc/$COPROC_PID/fd | grep 'pipe'
  1. Создаем со-процесс
  2. Выводим содержимое массива COPROC
  3. Выводим каналы текущей оболочки.
  4. Выводим каналы со-процесса.

Смотрим на имена, биты разрешений (r/w) ссылок и на что они указывают.

Как сказал один западный эксперт:

Вот такие пироги, изучай.