В системе GNU, и если у вас есть pv, вы можете сделать:
cmd='
that command | to execute &&
as shell code'
yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
-P20Это выполнить не более 20 $cmdодновременно.
-L10 ограничивает скорость до 10 байтов в секунду, поэтому 5 строк в секунду.
Если у вас $cmdдва медленных и приводит к достижению предела 20, то xargsчтение прекратится, пока $cmdне вернется хотя бы один экземпляр. pvбудет продолжать запись в канал с той же скоростью, пока канал не заполнится (что в Linux с размером канала по умолчанию 64 КБ займет почти 2 часа).
В этот момент pvперестану писать. Но даже тогда, когда xargsвозобновит чтение, pvпопытается перехватить и отправить все строки, которые должны были быть отправлены ранее, как можно быстрее, чтобы поддерживать среднее значение 5 строк в секунду.
Это означает, что до тех пор, пока это будет возможно с 20 процессами, удовлетворяющими этим 5 запускам в секунду в среднем требовании, он будет делать это. Однако при достижении предела скорость запуска новых процессов будет зависеть не от таймера pv, а от скорости, с которой возвращаются более ранние экземпляры cmd. Например, если 20 в данный момент работают и были в течение 10 секунд, и 10 из них решили завершить все одновременно, то 10 новых будут запущены одновременно.
Пример:
$ cmd='date +%T.%N; exec sleep 2'
$ yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
09:49:23.347013486
09:49:23.527446830
09:49:23.707591664
09:49:23.888182485
09:49:24.068257018
09:49:24.338570865
09:49:24.518963491
09:49:24.699206647
09:49:24.879722328
09:49:25.149988152
09:49:25.330095169
В среднем это будет 5 раз в секунду, даже если задержка между двумя запусками не всегда будет ровно 0,2 секунды.
С ksh93(или с, zshесли ваша sleepкоманда поддерживает доли секунды):
typeset -F SECONDS=0
n=0; while true; do
your-command &
sleep "$((++n * 0.2 - SECONDS))"
done
Это не ограничивает число одновременных your-commands.