LINUX.ORG.RU

Разделить stdin на несколько процессов и управлять их ходом

 , tee


0

1

Есть скрипт, который берёт файл с изображением, преобразует его с разными наборами параметров (для простоты — гаммы) и сохраняет ещё 7 вариантов. Затем полученный набор изображения распознаются Tesseract-ом.

Хочется сделать то же самое с буфером обмена без сохранения промежуточных файлов. Желательно иметь возможность ограничивать число процессов.

Скрипт варьирования гаммы:

for g in 2 4 8 0.5 0.25 0.125 0.0625
    do
        sem -j8 --quote convert "$filename" -gamma $g "`basename "$filename" .jpg`"-$g.jpg; 
    done

Скрипт распознавания содержимого буфера обмена:

xclip -out -selection clipboard -target image/jpeg | { tesseract - - -l rus+eng+ukr+fra+spa; echo ; } | xclip -selection clipboard -in

(Формат JPEG — из-за проблем в Тессеракте.)

Мне нужно направить stdin в несколько процессов, затем последовательно собрать их stdout-ы и направить в буфер. Всюду рекомендуют tee, но он направляет на stdout и исходный бинарный битмап. Пока получилось что-то вроде:

function cr  () ( tesseract - - -l rus+eng+ukr+fra+spa; echo ; )

function vg () ( echo $1; convert - -gamma $1 -format jpeg - | cr )

xclip -out -selection clipboard -target image/jpeg | tee  \
    >( echo 1; cr ) \
    >( vg 2 ) \
    >( vg 4 ) \
    >( vg 8 ) \
    >( vg 0.5 ) \
    >( vg 0.25 ) \
    >( vg 0.125 ) \
    >( vg 0.0625 ) \
    | xclip -selection clipboard -in

Проблемы следующие:

  1. Все echo отрабатывают одновременно, не дожидаясь окончания convert и tesseract. Как сделать, чтобы результат подпроцесса шёл на stdout одной порцией по завершению подпроцесса? (Пока ставлю echo в конец, но это не столь удобно.)
  2. Не всегда удобно запускать 8 процессов одновременно. Иногда нужно ограничить их число 4 или даже 1. Как это сделать?
  3. Как в tee лучше заблокировать вывод исходного stdin? Или чем заменить tee? — ОТВЕТ: ... | tee >(...) >(...) > /dev/null | ...
  4. Как это записать покороче? Строки я сократил, вынеся всё в функции, но как разместить под tee цикл?
  5. Если выполняю скрипт в шелле без последней команды — без редиректа в xclip — получаю ошибки «bash: 62: команда не найдена», «bash: 1: команда не найдена», «bash: 4c: команда не найдена» и непонятно откуда в истории команд шелла появляется 62;1;4c. Что это? — ОТВЕТ: Побочный эффект от вывода JPEG в консоль.
★★★★★

Последнее исправление: question4 (всего исправлений: 3)

Прочитал вскользь

Сложилось впечатление, что проще сгенерировать (автоматически) N скриптов с необходимыми параметрами, чем запускать N раз в одном скрипте чудеса с мультиплексированием stdin/stdout

gagarin0
()

Какой ещё «исходный stdin»? Что ты tee а вход подал - то он на выход и пишет. Вход у него ровно один - так что разбирайся с конвеером перед tee о том, что он не те данные шлёт. Впрочем, я не понял что конкретно ты хочешь и что пошло не так.

firkax ★★★★★
()

Все echo отрабатывают одновременно, не дожидаясь окончания convert и tesseract. Как сделать, чтобы результат подпроцесса шёл на stdout одной порцией по завершению подпроцесса?

Используй локфайлы например (это если ты хочешь именно такой способ мультиплексирования как у тебя). Но я кстати не уверен что это будет работать - возможно у tee переполнится выходной буфер, пока потребители будут ждать свои локфайлы, и всё в итоге зависнет. Либо есть другой вариант, без tee: конвеер выводишь во временный файл вместо tee, а потом по очереди применяешь к нему все эти cr и vg - они тогда в таком порядке выполняться и будут. По-моему такой вариант проще и наглядней, главное только имя файла правильно сделать чтобы ни с кем не конфликтовало.

Не всегда удобно запускать 8 процессов одновременно. Иногда нужно ограничить их число 4 или даже 1. Как это сделать?

Не вижу в чём проблема. Сколько надо столько и запускай.

Как в tee лучше заблокировать вывод исходного stdin? Или чем заменить tee?

Уже ответил - это какая-то чушь, у tee кроме исходного stdin ничего нет.

Если выполняю скрипт в шелле без последней команды — без редиректа в xclip — получаю ошибки «bash: 62: команда не найдена»

Не знаю. Могу предположить что где-то конвеер попадает на вход баша.

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

Named pipes и… https://man7.org/linux/man-pages/man1/tee.1.html

Tee меня не устраивает, сразу написал. Где читать про named pipes и как избежать проблем с доступом к /dev/fd/61, /dev/fd/62, /dev/fd/63 ?

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

рекомендуют tee, но он направляет на stdout и исходный бинарный битмап

Tee меня не устраивает

чем не устраивает-то? тем, что ты с ним не разобрался?

your-heroboras | tee ./named_pipe1 ./named_pipe2 > /dev/null и, внезапно, в stdout он больше ничего не направляет.

Где читать про

в интернете читать, в гуголе…

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

Какой ещё «исходный stdin»? Что ты tee а вход подал - то он на выход и пишет.

Вот про этот поток и спрашиваю.

Вход у него ровно один - так что разбирайся с конвеером перед tee о том, что он не те данные шлёт.

Входящий поток меня устраивает. Но мне нужно, чтобы этот поток не шёл дальше tee. Я попробовал pee из moreutils, но пока получаю ошибки доступа к /dev/fd/61, /dev/fd/62, /dev/fd/63.

Используй локфайлы например
конвеер выводишь во временный файл

Как сделать вообще без файлов? Я вызываю эти скрипты горячей клавишей в KDE. Где будет текущая директория? И с какими правами будет выполняться? Иногда что-то падает, поэтому не хочу оставлять мусорные файлы неизвестно где. И с оставшимися с прошлых раз файлами может быть путаница.

возможно у tee переполнится выходной буфер

Какой у него объём? Объём картинок — до мегабайта в самом худшем случае, объём текста — несколько килобайт.

question4 ★★★★★
() автор топика

Не всегда удобно запускать 8 процессов одновременно. Иногда нужно ограничить их число 4 или даже 1. Как это сделать?

Я б в цикле, который проверяет количество фоновых процессов, и когда их достаточно, то wait -n

papin-aziat ★★★★★
()
Последнее исправление: papin-aziat (всего исправлений: 1)

посмотри в сторону parallel, man parallel_examples. он по умолчанию группирует вывод по процессу.

function cr() { tesseract - - -l rus+eng+ukr+fra+spa; echo ; }
function vg() { echo $2; convert "$1" -gamma $2 -format jpeg - | cr }

TMPFILE=$(mktemp).jpg
xclip -out -selection clipboard -target image/jpeg > "$TMPFILE"

export -f cr vg
parallel --jobs 4  vg  ::: "$TMPFILE" ::: 2 4 8 0.5 0.25 0.125 0.0625 \
    | xclip -selection clipboard -in

rm "$TMPFILE"

я не проверял работает или нет.

anonymous
()
mkfifo fifo1 fifo2 fifo3 ... fifoN 
cat fifo1 fifo2 fifo3 ... fifoN | xclip & 
xclip | tee >(process1 > fifo1) >(process2 > fifo2) >(process3 > fifo3) ... >(process3 > fifoN)
wait
rm fifo1 fifo2 fifo3 ... fifoN
anonymous
()
Ответ на: комментарий от aol

Зачем?! Передай их имена через -f или какой там ключ в other-heroboras для указания входных файлов

Правильный ответ: пайпы всё нормально передают. Редирект в /dev/null действует только на исходный поток, проходящий сквозь tee. Спасибо!

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

посмотри в сторону parallel,

sem в стартовом посте эквивалентен parallel --semaphore Спасибо за совет, им можно группировать.

Но я хочу вообще без временных файлов. Как-то можно объединить несколько запусков parallel?

P.S. Ага, в мануале нашёлся пример с tee.

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

bash, куча сторонних утилит, parallel на perl.

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

Гонять питон жирно, и с бинарниками в буфере там сложно; переписывать xclip, Tesseract, ImageMagic и Coreutils не собираюсь; переписать parallel на bash квалификации не хватит.

Можешь предложить скрипт на перле?

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

Но мне нужно, чтобы этот поток не шёл дальше tee

Тогда добавь в конец > /dev/null , либо одну из команд который получают копии потока замени на шелл-конвеер чтоб она этот stdout принимала.

Как сделать вообще без файлов? Я вызываю эти скрипты горячей клавишей в KDE. Где будет текущая директория? И с какими правами будет выполняться? Иногда что-то падает, поэтому не хочу оставлять мусорные файлы неизвестно где. И с оставшимися с прошлых раз файлами может быть путаница.

Текущая директория тебя беспокоить не должна (пропиши абсолютные пути), а права, разумеется, того юзера который залогинен и запустил KDE. Насчёт оставшихся файлов - сделай всё аккуратно и проблем не будет. Вообще без файлов на шелле скорее всего не получится, он не для такого сделан. Можно без файлов сделать на Си.

Какой у него объём? Объём картинок — до мегабайта в самом худшем случае, объём текста — несколько килобайт.

Не знаю, вполне может оказаться что там только ядерный буфер конвеера который порядка нескольких кб. Проверь: cat /dev/zero | tee >(sleep 36000) tee-test & (sleep 1; killall tee ; wc tee-test) у меня выходит что он может не больше 64кб данных обработать если на той стороне их не читают.

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

Странно, по идее с ними та же проблема размера буфера должна быть. cat не начнёт читать fifo2 пока не дочитает до конца fifo1, а значит process2 скорее всего зависнет когда заполнит выводной буфер, а значит tee тоже зависнет когда заполнит буфер отправки в process2, который тот не читает.

firkax ★★★★★
()

Интересный эффект: экземпляры tesseract завершаются в порядке, обратном перечисленному в скрипте. То есть 0.0625 - 0.125 - 0.25 - 0.5 - 8 - 4 - 2 - 1.

question4 ★★★★★
() автор топика