5

I would like to do:

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

I have a feeling that it can be written fairly close to:

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

The problem I am trying to solve is that program reads from stdin but crashes if it gets no input. I do not have access to the source for program thus program cannot be changed. The binary input is bigger than the memory size so putting stdin to a file first is unacceptably slow. Processing all the input line-by-line in bash is unacceptably slow also.

The solution should ideally work under both csh and bash.

Carl B
  • 6,660
Ole Tange
  • 5,099

5 Answers5

2

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.

Ole Tange
  • 5,099
1

Try reading a line from stdin first:

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
glenn jackman
  • 27,524
1

If you don't want your script to block in an attempt to look for something to read, you can (at least in bash) use a read with timeout

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

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

This however does not guarantee that you have EOF but that there is nothing to read at the moment

Hachi
  • 161
0

What kind of input is your program expects ? are you piping the output from one program to the other or is it reading a file ?

If you are using pipe redirection to collect input to ur script then it will proceed executing till the input supply is provided.

if you are trying to read from a file then use "while" or "until" to do the job.

Kannan Mohan
  • 458
  • 2
  • 6
0

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) ${BASH_VERSINFO[*]}

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 %)

vike
  • 101