[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: non-blocking stdin from bash



On Sun, 2018-08-12 at 10:36 +0200, tomas@tuxteam.de wrote:
> On Sun, Aug 12, 2018 at 01:26:40AM -0400, Jim Popovitch wrote:
> > On Sun, 2018-08-12 at 00:48 +0200, tomas@tuxteam.de wrote:
> > > On Sat, Aug 11, 2018 at 06:08:34PM -0400, Jim Popovitch wrote:
> > > > Hello!
> > > > 
> > > > What's the best way to grab anything that's in stdin into a
> > > > variable
> > > > inside a bash script, but won't block if stdin is null?
> > > 
> > > I think read is your friend (at least in bash). It has an option
> > > -t <timeout>, which you can set to zero, for it to just grab
> > > what's
> > > available at the moment without waiting (cf "help read" while in
> > > the bash for more details, like setting a delimiter, etc.)
> > > 
> > > HTH
> > > -- tomás
> > 
> > Thanks for the reply tomás.  I'm trying to avoid using read because
> > of
> > the 1 sec minimum timeout.
> 
> Not on bash, at least. According to the docs, "-t 0" is a timeout of
> zero. Experiments confirm that:
> 
>   tomas@trotzki:~$ time read -t 0
> 
>   real    0m0.000s
>   user    0m0.000s
>   sys     0m0.000s
> 
> (Of course, 0 is too optimistic here, but it's sub-millisecond).
> Fractional times work too:
> 
>   tomas@trotzki:~$ time read -t 0.05
> 
>   real    0m0.050s
>   user    0m0.000s
>   sys     0m0.000s
> 
> Finally, you can use timeout to read incomplete (i.e. non-terminated)
> input, like so:
> 
>   tomas@trotzki:~$ time echo -n mumble | bash -c 'read -t 0.01 foo ;
> echo $foo'
>   mumble
> 
>   real    0m0.004s
>   user    0m0.000s
>   sys     0m0.000s
> 
> Note that "-t 0" won't work here: the "read" at the right is there
> before
> the "echo" at the left, so read turns out empty...
> 
> >                             This may seem odd, but 1 sec is 100+
> > times
> > longer than grep'ing/awk'ing/sed'ing the contents of a variable, so
> > I'm
> > trying to find a faster way to read stdin.  
> 
> No, it doesn't seem odd. Sometimes 1 sec is too much (sometimes 1msec
> is
> too much, too :-)
> 
> But I think (used wisely) read is still your friend!
> 
> Note that I didn't check how much of this is bashism. Document your
> requirements :-)

:-)

Turns out I had mis-read your first reply as "-t 1", chiefly because
that was all that I had found before posting here.  What now works for
me avoids the -t param:


while read stdin_line
do
   MSG=$MSG"\n"$stdin_line
done < /dev/stdin


Thanks again,

-Jim P.


Reply to: