Предотвращать автоматическую отправку EOF в именованный канал и отправлять EOF, когда мне это нужно

Предотвращать автоматическую отправку EOF в именованный канал и отправлять EOF, когда мне это нужно

У меня есть программа, которая автоматически завершает работу при чтении EOF в заданном потоке (в следующем случае, stdin).
Теперь я хочу создать скрипт оболочки, который создаст именованный канал и подключит к нему stdin программы. Затем скрипт пишет в каналнесколько разс помощью echoи cat(и других инструментов, которые автоматически генерируют EOF при выходе). Проблема, с которой я столкнулся, заключается в том, что когда первый echoвыполнен, он отправляет EOF в конвейер и заставляет программу завершиться. Если я использую что-то вроде , tail -fто я не могу отправить EOF, когда собираюсь выйти из программы. Я ищу сбалансированное решение, но безуспешно.
Я уже нашел и то, как предотвратить EOF, и то, как вручную отправить EOF, но я не могу их объединить. Есть ли какая-нибудь подсказка?

#!/bin/sh
mkfifo P
program < P & : # Run in background
# < P tail -n +1 -f | program
echo some stuff > P # Prevent EOF?
cat more_stuff.txt > P # Prevent EOF?
send_eof > P # How can I do this?
# fg

решение1

Как уже указывали другие, читатель канала получает EOF, когда не осталось ни одного писателя. Поэтому решение состоит в том, чтобы всегда был один писатель, держащий канал открытым. Этот писатель не должен ничего отправлять, просто держит его открытым.

Поскольку вы используете скрипт оболочки, самое простое решение — сказать оболочке открыть канал для записи. А затем закрыть его, когда закончите.

#!/bin/sh
mkfifo P
exec 3>P # open file descriptor 3 writing to the pipe
program < P
# < P tail -n +1 -f | program
echo some stuff > P
cat more_stuff.txt > P
exec 3>&- # close file descriptor 3

Обратите внимание, что если вы пропустите последнюю строку, дескриптор файла 3 будет автоматически закрыт (и, таким образом, читатель получит EOF) при выходе из скрипта. Помимо удобства, это также обеспечивает своего рода безопасность, если скрипт каким-то образом завершится раньше времени.

решение2

Канал получает EOF, когда последний писатель уходит. Чтобы избежать этого, убедитесь, что всегда есть писатель (процесс, который держит канал открытым для записи, но на самом деле ничего не пишет). Чтобы отправить EOF, заставьте этого резервного писателя уйти.

mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
  kill $P_writer_pid
}

решение3

Программа не может отличить EOF, означающий «пора заканчивать», от EOF, означающего «писатель закончил, но может быть еще кто-то внес свой вклад».

Если у вас есть возможность изменять поведение вашей программы, то выполните чтение в бесконечном цикле (одна итерация длится до EOF) и отправьте ей определенную командную строку, которая означает «пора выходить». Отправка этой строки будет задачей команды send_eofв вашем вопросе.

Другой вариант:

( echo some stuff; cat more_stuff.txt ) >P

или

{ echo some stuff; cat more_stuff.txt; } >P

Связанный контент