Как котировать именованный канал без ожидания

Как котировать именованный канал без ожидания

Если в именованном канале ничего нет и я делаю:

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 catas на <"$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.

Возможно, это не самое чистое решение, но оно выполняет свою функцию.

Надеюсь, поможет.

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