Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question
1  
You have to read a stream before you can test for EOF. Sounds like you have a poorly designed script. –  fpmurphy1 Dec 20 '12 at 9:27
    
Well, what is that program which crashes? Wouldn't it be better to try and get it not to crash? –  slhck Dec 20 '12 at 12:32

4 Answers 4

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.

share|improve this answer
    
This should be a comment for the question, not an answer –  glenn jackman Dec 20 '12 at 16:01
    
@glenn: I disagree. @M is asking a question about the question only to illuminate the situations in which each of his two answers apply. … // … I agree that it isn’t a good answer, but it is an answer. –  Scott Dec 20 '12 at 21:55

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
share|improve this answer
    
Your answer fails if the first line of the input is a blank line. I suggest if IFS= read -r line; then …. Or, if the input might be an incomplete line (e.g., echo "The quick brown fox jumps …\c" | OleTange.sh), do if IFS= read -r line  ||  [[ -n "$line" ]]; then …. –  Scott Dec 20 '12 at 22:05
    
I like the idea. It does impose a limit that there must be a \n before size of memory amount of data, which is suboptimal, but might be an acceptable limit. Also it seems not to work if the first \0 is before the first \n, which is not acceptable as the input is binary data. E.g: printf "abc\0def\nghi\njkl" | if ... . Can we ask read to read a number of bytes (incl \0) instead of a full line? –  Ole Tange Dec 21 '12 at 23:05
    
read -N 1 seems to help, but fails if the first char is \0. –  Ole Tange Dec 21 '12 at 23:29
up vote 1 down vote accepted

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.

share|improve this answer

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

share|improve this answer
    
Would be wonderful if it worked in general. But alas it does not: /dev/fd/* does not exist on hurd, aix, hpux, qnx, tru64, ultrix. /dev/stdin does not exist on irix, aix, hpux, tru64, ultrix. –  Ole Tange Jun 9 at 18:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.