Если вы хотите иметь возможность читать содержимое после закрытия дескриптора файла, вам нужно просто использовать файлы. Мысль о каналах заключается в том, что команда чтения должна выполняться в первую очередь перед командой, которая пишет.
При такой настройке:
cmd1 | cmd2 | cmd3
Сначала запускается
cmd3
, затем cmd2
, затем cmd1
. Поэтому, если вы хотите настроить его с помощью каналов, вам нужно будет открыть каждый fifo для параллельного чтения, а затем вызвать printer
:
printer() {
echo "OUT" >&1
echo "ERR" >&2
echo "WRN" >&3
}
# Usage: mux
mux() {
cat "${pipe1}" &
cat "${pipe2}" &
cat "${pipe3}"
}
mux &
printer 1>${pipe1} 2>"${pipe2}" 3>"${pipe3}"
Оболочка будет блокироваться по этому фрагменту:
(exec >"${pipe1}" 2>"${pipe2}"; echo "Test"; echo "Test2" >&2) &
cat < "${pipe1}"
cat < "${pipe2}"
Вкл. cat < "$pipe1"
Причина, по которой необходимо выполнить чтение из обоих каналов, чтобы exec продолжил:
(exec >"${pipe1}" 2>"${pipe2}"; echo "Test"; echo "Test2" >&2) &
cat < "${pipe1}" &
cat < "${pipe2}"
Если вы хотите получить буферизованный вывод команды, т.е. прочитайте вывод команды после того, как она что-то написала или вышла, используйте для этого только файлы, они на самом деле называются журналами.
В качестве обходного пути вы можете использовать внутреннюю буферизацию bash pipe для буферизации ваших сообщений:
printer() {
echo "OUT" >&3
echo "ERR" >&4
echo "WRN" >&5
}
# Usage: mux
mux() {
timeout 1 cat "${pipe1}"
timeout 1 cat "${pipe2}"
timeout 1 cat "${pipe3}"
}
printer 3> >(cat >$pipe1) 4> >(cat >$pipe2) 5> >(cat >$pipe3)
mux
Что здесь происходит, так это то, что каналы всегда открыты для записи, даже после того, как функция принтера существует, и будут оставаться открытыми, пока не будет запущена замена процесса. Вы можете закрыть их вручную, с помощью exec 5>&-
, что запишет EOF в канал, позволяя cat $pipe3
вернуться нормально. cat "$pipe1"
никогда не завершится, если функция не закрывает файловые дескрипторы, поэтому используются функции тайм-аута, чтобы мы могли сливать каналы, не блокируя их.