Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Nov 2010 15:03:18 -0800
From:      Devin Teske <dteske@vicor.com>
To:        "Carlos A. M. dos Santos" <unixmania@gmail.com>
Cc:        FreeBSD Hackers <freebsd-hackers@freebsd.org>
Subject:   Re: Spinner Function for Shell Scripts
Message-ID:  <2CCA101F-22FA-4CE2-8F4C-117824CEA104@vicor.com>
In-Reply-To: <AANLkTi=Us-OoLHpO2YPM4VCgFUQM2BX3jcPSaJnXF9rG@mail.gmail.com>
References:  <1289506363.30235.113.camel@localhost.localdomain> <AANLkTi=Us-OoLHpO2YPM4VCgFUQM2BX3jcPSaJnXF9rG@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

On Nov 13, 2010, at 1:19 PM, Carlos A. M. dos Santos wrote:

> On Thu, Nov 11, 2010 at 6:12 PM, Devin Teske <dteske@vicor.com> wrote:
>> Hi fellow hackers... I come with baring gifts!
>>=20
>> So, just as the subject-line says, ... here's an efficient and robust
>> spinner function compatible with many shells.
>>                        DONE=3D$( /bin/sh -c 'read -t 0 DONE; echo =
$DONE' )
>=20
> Is this expected to be portable to other operating systems? The dash
> shell, used as /bin/bash in Ubuntu, does not acept the "-t" argument
> to the read builtin command. Using /bin/bash solves the problem.

I was shooting for bourne-shell, but later realized that bash's read =
statement functions fundamentally different than bourne's (hence the =
direct invocation of /bin/sh).

On FreeBSD:

$ echo 'Hello' | /bin/sh -c 'read -t 0 DONE; echo $DONE'
Hello
$ echo 'Hello' | /bin/bash -c 'read -t 0 DONE; echo $DONE'

$ echo 'Hello' | /bin/bash -c 'read -t 1 DONE; echo $DONE'
Hello
$ /bin/bash -c 'read -t 0.5 DONE; echo $DONE'
/bin/bash: line 0: read: 0.5: invalid timeout specification

As you can see from the above, passing a timeout specification of zero =
to bourne-shell has the desired effect... if the stdin file descriptor =
has something to offer the read-statement, input will be read up-to the =
ending newline. Whereas, you can see that bash's implementation returns =
nothing from the read despite data being available. Naturally, one can =
get the data into bash's read by using a timeout of one, but that would =
be unacceptable to our spinner to rotate the spinner one-quarter spin =
each second. Last, the potential work-around of using finer measurements =
of time is not allowed.

However, this shouldn't be considered a bug, given the following =
description of the timeout option in bash's InfoTex manual:

    `-t TIMEOUT'
          Cause `read' to time out and return failure if a complete
          line of input is not read within TIMEOUT seconds.  This
          option has no effect if `read' is not reading input from the
          terminal or a pipe.

Now, compare that with the description from bourne-shell's man-page =
(sh(1)):

             If the -t option is specified and the timeout elapses =
before any
             input is supplied, the read command will return without =
assigning
             any values.  The timeout value may optionally be followed =
by one
             of ``s'', ``m'' or ``h'' to explicitly specify seconds, =
minutes
             or hours.  If none is supplied, ``s'' is assumed.

So, as you can see, bash will timeout if a full line is not received in =
the duration specified as the timeout, while bourne-shell will timeout =
only if no input is supplied for the same duration.

For our purposes, we want bourne-shell's implementation, not bash's (at =
least on FreeBSD).

I also tested Mac OS X 10.6.1, FreeBSD-8.1, CentOS 4.7, RedHat =
Enterprise Linux (RHEL) 4 Nahant Update 4 (U4), and also RHEL4U8.

Here's the breakdown for the test of ``read -t 0 LINE; echo $LINE'':

Mac OS X 10.6.1:
	sh: FAIL
	bash: FAIL
RedHat Enterprise Linux (RHEL) 4 Update 4 (U4):
	sh: FAIL
	bash: FAIL
RedHat Enterprise Linux (RHEL) 4 Update 8 (U8):
	sh: FAIL
	bash: FAIL
CentOS 4.7:
	sh: FAIL
	bash: FAIL
FreeBSD-4.8:
	sh: SUCCEED
	bash: FAIL
FreeBSD-4.11:
	sh: SUCCEED
	bash: FAIL
FreeBSD-8.1:
	sh: SUCCEED
	bash: FAIL

This is not so surprising... On all of the above-tested Linux OSes, =
/bin/sh is a symbolic link to bash(1). On Mac OS X, /bin/sh is simply a =
bash binary (try /bin/sh --version).

It's rather unfortunate that bourne-shell has what we need but is not =
available on all operating systems since many OSes have started swapping =
out bourne-shell for it's younger cousin.

Does anyone else happen to know of a portable way to quickly check if =
data is available on a given file descriptor?
--
Cheers,
Devin Teske

-> CONTACT INFORMATION <-
Business Solutions Consultant II
FIS - fisglobal.com
510-735-5650 Mobile
510-621-2038 Office
510-621-2020 Office Fax
909-477-4578 Home/Fax
devin.teske@fisglobal.com

-> LEGAL DISCLAIMER <-
This message  contains confidential  and proprietary  information
of the sender,  and is intended only for the person(s) to whom it
is addressed. Any use, distribution, copying or disclosure by any
other person  is strictly prohibited.  If you have  received this
message in error,  please notify  the e-mail sender  immediately,
and delete the original message without making a copy.

-> END TRANSMISSION <-




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?2CCA101F-22FA-4CE2-8F4C-117824CEA104>