Если в именованном канале ничего нет и я делаю:
cat my_named_pipe
он будет ждать, пока не поступят данные. Есть ли флаг, который я могу использовать для немедленного выхода, если нет данных для чтения? Или, может быть, команда, отличная от cat, которую я могу использовать?
Я также попробовал:
read val < "$my_named_pipe";
но это также ждёт следующего фрагмента данных - я не хочу ждать, если fifo пуст.
решение1
Чтобы предотвратить cat
зависание при отсутствии какого-либо писателя (в этом случае зависает открытие fifo, а не чтение из него), можно сделать следующее:
cat 0<> "$my_named_pipe" <"$my_named_pipe"
Первое перенаправление открывается в режиме чтения+записи, который в большинстве систем не блокируется и создает экземпляр канала, даже если нет ни писателя, ни читателя. Затем второе открытие (на этот раз только для чтения) не будет блокироваться, поскольку теперь есть по крайней мере один писатель (он сам).
Требуется 0
только в последних версиях ksh93, где fd по умолчанию <>
изменен с 0 на 1.
Также, в ksh93
, это не сработает, когда cat
встроена оболочка, например, когда ksh93
вызывается, когда /opt/ast/bin
находится перед /bin
или $PATH
после вызова builtin cat
as на <"$my_named_pipe"
, (я полагаю) ksh93 сохраняет предыдущую цель stdin в отдельном файловом дескрипторе, который будет держать канал открытым. Вы можете обойти это, написав вместо этого:
cat 3<> "$my_named_pipe" <"$my_named_pipe" 3<&-
(что, как вы также можете утверждать, более четко передает намерение)
Обратите внимание, что это <>
на канале также разблокирует других читателей в fifo.
Если бы были некоторые писатели, cat
все равно пришлось бы читать весь их вывод и ждать, пока они не закроют свой конец канала. Вы могли бы открыть канал в неблокирующем режиме, как с GNU dd
:
dd bs=64k if="$my_named_pipe" iflag=nonblock status=noxfer
Который будет считывать данные из канала только до тех пор, пока в нем есть какие-то данные, и завершаться с сообщением
dd: error reading 'fifo': Resource temporarily unavailable
ошибка, когда больше нет, и не разблокировать других читателей, но это означает, что вы можете пропустить часть выходных данных писателей, если они медленнее записывают в канал, чем вы ( dd
) читаете его.
Другой подход может заключаться в тайм-ауте, если в течение некоторого времени не было ввода, например, с помощью socat
опции -T
:
socat -u -T1 - - 0<> "$my_named_pipe" <"$my_named_pipe"
Который бы прекратился, если бы в течение секунды из трубы ничего не выходило.
решение2
Что-то совсем простое — немедленно завершить cat
после чтения fifo, независимо от того, есть ли там данные или нет. Вы можете сделать это с помощью timeout
, как показано ниже:
timeout 2 cat my_named_pipe
Выше, timeout
ждет две секунды, прежде чем заставить cat завершиться. Если что-то буферизовано в именованном канале при запуске cat
, оно будет выведено на stdout.
Возможно, это не самое чистое решение, но оно выполняет свою функцию.
Надеюсь, поможет.