Bash / csh: проверка конца файла (EOF) стандартного ввода

5687
Ole Tange

Я хотел бы сделать:

if not eof(stdin): pass stdin to program else: do nothing 

У меня есть ощущение, что это может быть написано довольно близко к:

if test ! --is-eof - ; then exec program 

Проблема, которую я пытаюсь решить, заключается в том, что programчитает из стандартного ввода, но падает, если он не получает ввода. У меня нет доступа к источнику, programпоэтому programне может быть изменено. Бинарный ввод больше, чем объем памяти, поэтому ввод stdin в файл сначала недопустимо медленен. Строковая обработка всех входных данных в bash также недопустимо медленная.

В идеале решение должно работать как под csh, так и под bash.

2
Вы должны прочитать поток, прежде чем сможете проверить EOF. Похоже, у вас плохо разработан сценарий. fpmurphy1 11 лет назад 2
Ну, что это за программа, которая вылетает? Разве не было бы лучше попытаться заставить это не терпеть крах? slhck 11 лет назад 0

5 ответов на вопрос

1
glenn jackman

Попробуйте сначала прочитать строку из stdin:

IFS= read -r line if [[ -n "$line" ]]; then # the line is non-empty. # add the line back into the stream and pipe it into your program { echo "$line"; cat -; } | your_program fi 
Ваш ответ не получится, если первая строка ввода будет пустой строкой. Я предлагаю `if IFS = read -r line; тогда… Или, если входные данные могут быть неполной строкой (например, `echo" Быстрый коричневый лис прыгает ... \ c "| OleTange.sh`), выполните` if IFS = read -r line || [[-n "$ line"]]; тогда… Scott 11 лет назад 0
Мне нравится идея. Это налагает ограничение, которое должно быть \ n до размера памяти, которое является неоптимальным, но может быть приемлемым пределом. Кроме того, кажется, что это не работает, если первый \ 0 находится перед первым \ n, что недопустимо, поскольку входные данные являются двоичными данными. Например: printf "abc \ 0def \ nghi \ njkl" | если ... . Можем ли мы попросить `read` прочитать количество байтов (вкл. \ 0) вместо полной строки? Ole Tange 11 лет назад 0
`read -N 1`, кажется, помогает, но завершается неудачно, если первый символ равен \ 0. Ole Tange 11 лет назад 0
1
Ole Tange

This seems to work in both csh and bash and deal nicely with binary input (also \0 as first char):

# Set $_FIRST_CHAR_FILE to the name of a temp file. eval `echo $SHELL | grep -E "/(t)?csh" > /dev/null && echo setenv _FIRST_CHAR_FILE /tmp/$$.first_char_file || echo export _FIRST_CHAR_FILE=/tmp/$$.first_char_file` dd bs=1 count=1 of=$_FIRST_CHAR_FILE >&/dev/null test -s "$_FIRST_CHAR_FILE" && ( cat $_FIRST_CHAR_FILE; rm $_FIRST_CHAR_FILE; cat - ) | program 

Thanks to @glenn-jackman for giving the idea of reading a little bit before passing this and the rest of stdin through cat.

0
Kannan Mohan

Какой ввод ожидает ваша программа? вы передаете вывод из одной программы в другую или он читает файл?

Если вы используете перенаправление канала для сбора входных данных в свой скрипт, то он будет выполняться до тех пор, пока не будет предоставлена ​​входная информация.

если вы пытаетесь читать из файла, используйте «while» или «then» для выполнения работы.

Это должен быть комментарий к вопросу, а не ответ glenn jackman 11 лет назад 0
@glenn: я не согласен. @M задает вопрос по этому вопросу только для того, чтобы осветить ситуации, в которых применяется каждый из двух его ответов. … //… Я согласен, что это не очень хороший ответ, но это ответ. Scott 11 лет назад 0
0
vike

I post here since this came up when searching and since it helped me debugging on Darwin (snow leopard) bash in set -x;trap 'test -s /dev/stdin||exit' debug to find a call that was consuming the inherited input of the parent script.

For the faint-hearted:

if [[ -s /dev/fd/0 ]] then echo 'Not at EOF' else echo 'Currently no input to read' fi 

Test:

echo $((echo|test -s /dev/stdin)&&! (true|test -s /dev/stdin)&&echo pass||echo fail) $ 

The above test yields the following in my bash versions and systems.

pass 4 2 45 2 release i386-apple-darwin10.8.0
pass 3 2 48 1 release x86_64-apple-darwin10.0
fail 4 2 37 1 release x86_64-pc-linux-gnu

Piping to cat /proc/self/fdinfo/0 on my Debian (wheezy) gives nothing to test for either.

CheerIO or rather cheerEO for Erroneous/Output %)

Было бы замечательно, если бы это работало в целом. Но, увы, его нет: / dev / fd / * не существует на HURD, AIX, HPUX, QNX, Tru64, ULTRIX. / dev / stdin не существует в irix, aix, hpux, tru64, ultrix. Ole Tange 9 лет назад 0
0
Hachi

Если вы не хотите, чтобы ваш скрипт блокировался при попытке найти что-то для чтения, вы можете (по крайней мере, в bash) использовать чтение с тайм-аутом

$ ( read -t 0 var ; echo $? ) 1  $ echo foo | ( read -t 0 var ; echo $? ) 0 

Это, однако, не гарантирует, что у вас есть EOF, но что сейчас нечего читать