Обычно при работе с трубами и стандартным вводом у истощенной трубы нет особого значения. Новые данные могут появляться до тех пор, пока не появится eof
канал, закрывающий канал. Ваш cat
заканчивается в eof
соответствии с ожиданиями. Если раньше не было никаких данных eof
, только тогда вы можете сказать, что stdin был действительно пуст.
Посмотрим sender | receiver
. Это не редкость sender
(намного) медленнее, чем receiver
; в этом случае стандартный receiver
ввод почти всегда исчерпан, но вы вряд ли захотите убить всю трубу из-за этого. Поэтому инструменты, которые выходят на «пустом» (истощенном, но еще не завершенном) стандартном вводе, являются скорее исключениями, чем стандартными.
В Bash есть read -t 0
( -t
не требуется POSIX). От help read
:
Если
TIMEOUT
есть0
,read
возвращает немедленно, не пытаясь прочитать какие-либо данные, возвращая успех, только если входные данные доступны в указанном файловом дескрипторе.
По умолчанию read
читает из stdin, поэтому состояние выхода read -t 0
сообщит вам, является ли stdin «пустым». Но будьте осторожны! Команда как
echo 1 | read -t 0
может выйти успешно или нет, потому что echo
и read
работать одновременно, а не последовательно. Чтобы избежать этого, ваш скрипт должен sleep
на некоторое время раньше read -t 0
. В зависимости от того, откуда приходит stdin, «время» может быть относительно долгим. Сделайте что-то вроде этого:
sleep 1 if read -t 0; then … # process stdin here, you know it's non-empty
Вы заполняете переменную данными, взятыми из стандартного ввода. Поскольку хранить двоичные данные в переменной не очень хорошая идея (прочитайте это ), возможно, ваши данные - просто текст. Если так, используйте read -t
как это:
read -r -t 5 -d $'\0' stdin
Нулевой символ (который вы не можете сохранить в переменной Bash в любом случае) в качестве разделителя ( -d $'\0'
) позволит вам читать любой текст (например, с символами новой строки) в stdin
переменной. Через максимум 5 секунд ( -t 5
) команда завершается, что позволяет вашему сценарию продолжить.
Другой подход с timeout
. Базовый пример из моего Debian:
timeout --foreground 5 cat | wc -c
(Замените wc -c
своим кодом, который анализирует стандартный ввод; это всего лишь пример).
Это должно обрабатывать двоичные данные просто отлично. Если cat
не получится, eof
то через 5 секунд он будет убит, поэтому wc
все eof
равно получит, и линия не остановится. Проблема cat
будет убита независимо от того, обрабатывает ли она какие-либо данные в данный момент. Я полагаю, вы хотите получить все данные, если они есть, даже если это займет более 5 секунд. Улучшенная версия:
{ timeout --foreground 5 dd bs=1 count=1 2>/dev/null && cat; } | wc -c
Если первый байт появится в течение 5 секунд, cat
будет запущен. Затем он будет обрабатывать любые дальнейшие вводные данные eof
, независимо от того, сколько времени это займет. Все, включая первый байт (если есть), перейдет на wc
. Если нет ни байта, ни eof
через 5 секунд, wc
получит просто eof
; линия не останавливается.