Подтвердить что ты не робот

Как избежать эхо-закрытия FIFO именованных каналов? - Забавное поведение Unix FIFO

Я хочу вывести некоторые данные в канал, а другой процесс сделать что-то по строкам данных. Вот пример игрушки:

mkfifo pipe
cat pipe&
cat >pipe

Теперь я могу ввести все, что захочу, и после нажатия enter я сразу вижу ту же строку. Но если заменить вторую трубку на echo:

mkfifo pipe
cat pipe&
echo "some data" >pipe

Труба закрывается после завершения echo и cat pipe&, чтобы я не мог передавать больше данных через трубу. Есть ли способ избежать закрытия трубы и процесса, который получает данные, чтобы я мог передавать много строк данных через канал из bash script и обрабатывать их по мере их поступления?

4b9b3361

Ответ 1

Когда FIFO открывается для чтения, он блокирует вызывающий процесс (обычно). Когда процесс открывает FIFO для записи, читатель разблокируется. Когда автор закрывает FIFO, процесс чтения получает EOF (0 байт для чтения), и больше ничего не может быть сделано, кроме закрытия FIFO и повторного открытия. Таким образом, вам нужно использовать цикл:

mkfifo pipe
(while cat pipe; do : Nothing; done &)
echo "some data" > pipe
echo "more data" > pipe

Альтернативой является сохранение некоторого процесса с открытием FIFO.

mkfifo pipe
sleep 10000 > pipe &
cat pipe &
echo "some data" > pipe
echo "more data" > pipe

Ответ 2

Поместите все операторы, которые вы хотите вывести на fifo в одной и той же подоболочке:

# Create pipe and start reader.
mkfifo pipe
cat pipe &
# Write to pipe.
(
  echo one
  echo two
) >pipe

Если у вас есть еще сложнее, вы можете открыть канал для записи:

# Create pipe and start reader.
mkfifo pipe
cat pipe &
# Open pipe for writing.
exec 3>pipe
echo one >&3
echo two >&3
# Close pipe.
exec 3>&-

Ответ 3

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

Итак, измените свой второй пример на:

mkfifo pipe
cat <>pipe &
echo "some data" >pipe

Ответ 4

В качестве альтернативы другим решениям здесь вы можете вызвать cat в цикле в качестве входа в свою команду:

mkfifo pipe
(while true ; do cat pipe ; done) | bash

Теперь вы можете подавать команды по одному и не закрывать:

echo "'echo hi'" > pipe
echo "'echo bye'" > pipe

Вам, конечно, придется убить процесс, если хотите. Я думаю, что это самое удобное решение, поскольку оно позволяет вам указать не выходящее поведение при создании процесса.

Ответ 5

Я улучшил вторую версию ответа Джонатана Леффлера, чтобы поддержать закрытие трубы:

dir=`mktemp -d /tmp/temp.XXX`
keep_pipe_open=$dir/keep_pipe_open
pipe=$dir/pipe

mkfifo $pipe
touch $keep_pipe_open

# Read from pipe:
cat < $pipe &

# Keep the pipe open:
while [ -f $keep_pipe_open ]; do sleep 1; done > $pipe &

# Write to pipe:
for i in {1..10}; do
  echo $i > $pipe
done

# close the pipe:
rm $keep_pipe_open
wait

rm -rf $dir