Обычно при работе с трубами и стандартным вводом у истощенной трубы нет особого значения. Новые данные могут все еще появляться, пока не будет eof
который закроет канал. Ваша cat
заканчивается в eof
как и ожидалось. Если бы не было никаких данных до eof
только тогда вы можете сказать , что STDIN был действительно пуст.
Рассмотреть sender | receiver
Нередко sender
(намного) медленнее, чем receiver
; в этом случае stdin 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
. Если в течение 5 секунд не будет ни байта, ни eof
, wc
получит только eof
; линия не останавливается.