[comp.unix.questions] Piping into Shell scripts

andy@syma.sussex.ac.uk (Andy Clews) (02/28/90)

Is there any way of getting a Shell script (C or Bourne) to recognise
whether it is receiving input from a pipe?

My script includes something like this:

	echo "Please enter message text and then enter a CTRL D"
	cat > foo
	etc.etc.

In some circumstances I might want to pipe text into the script, so I
don't want it to echo the prompt message.  I have RTFM (hope I haven't
missed something).  Can anyone help?

-- 
Andy Clews, Computing Service, Univ. of Sussex, Brighton BN1 9QN, England
JANET: andy@syma.sussex.ac.uk   BITNET: andy%syma.sussex.ac.uk@uk.ac

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/28/90)

In article <2283@syma.sussex.ac.uk> andy@syma.sussex.ac.uk (Andy Clews) writes:
: Is there any way of getting a Shell script (C or Bourne) to recognise
: whether it is receiving input from a pipe?

Sort of.

: My script includes something like this:
: 
: 	echo "Please enter message text and then enter a CTRL D"
: 	cat > foo
: 	etc.etc.
: 
: In some circumstances I might want to pipe text into the script, so I
: don't want it to echo the prompt message.  I have RTFM (hope I haven't
: missed something)...

You don't hope you didn't miss something, you hope you DID miss something.
Fortunately you did.

To do what you want (as opposed to what you asked for), say

	test -t 0 && echo "Please enter message text and then enter a CTRL D"

This will echo the message only if stdin is attached to a terminal.

To do what what you asked for (determine if it's a pipe) would take
a C program or a Perl script.  On a BSD system, where a pipe is a kind of
socket, you could say
	
	perl -e 'exit -S STDIN;' && echo "My prompt"

On a Sun (and probably AT&T systems) it's considered a FIFO, so you'd say

	perl -e 'exit -p STDIN;' && echo "My prompt"

Of course, why start an extra process?  Here's a portable version, and
you won't have to worry about how to suppress the newline on the prompt:

	perl -e 'print "My prompt" unless -S STDIN || -p STDIN;'

And, since you wanted -t anyway, just say:

	perl -e 'print "My prompt" if -t;'

I will refrain from suggesting that you write the whole script in Perl.  :-)

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

cpcahil@virtech.uucp (Conor P. Cahill) (02/28/90)

In article <2283@syma.sussex.ac.uk> andy@syma.sussex.ac.uk (Andy Clews) writes:
>Is there any way of getting a Shell script (C or Bourne) to recognise
>whether it is receiving input from a pipe?

tty(1) will report "not a tty" if it's input is not from a tty. 

So the following should work:

	testdata="`tty`"
	if [ "$testdata" = "not a tty" ]; then
		echo "we are not running from a terminal.  therefore we must"
		echo "be running from a pipe or with stdin redirected from a" 
		echo "file of some sort (of course, it also could be closed)"

		exit
	fi
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

decot@hpisod2.HP.COM (Dave Decot) (03/04/90)

> >Is there any way of getting a Shell script (C or Bourne) to recognise
> >whether it is receiving input from a pipe?
> 
> tty(1) will report "not a tty" if it's input is not from a tty. 
> 
> So the following should work:
> 
> 	testdata="`tty`"
> 	if [ "$testdata" = "not a tty" ]; then
> 		echo "we are not running from a terminal.  therefore we must"
> 		echo "be running from a pipe or with stdin redirected from a" 
> 		echo "file of some sort (of course, it also could be closed)"
> 
> 		exit
> 	fi

This is not portable: many systems output different messages for this
same condition, and some systems write the message on the standard
*error* output.  For instance, "Not a typewriter" is a message used
on some systems.

Instead, use:

	if tty -s
	then
	    echo "Running from a terminal"
	else
	    echo "Not running from a terminal"
	fi

Dave Decot

peter@ficc.uu.net (Peter da Silva) (03/08/90)

> > >Is there any way of getting a Shell script (C or Bourne) to recognise
> > >whether it is receiving input from a pipe?

... bunch of non-optimal answers deleted ...

if [ -t 0 ]
then
  echo "Standard Input is a terminal"
else
  echo "Standard input is not a terminal"
fi

Often, test ("[...]") is a builtin, saving you a fork/exec.
-- 
 _--_|\  `-_-' Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
/      \  'U`
\_.--._/
      v

gwyn@smoke.BRL.MIL (Doug Gwyn) (03/08/90)

In article <IL22A+1xds13@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>> > >Is there any way of getting a Shell script (C or Bourne) to recognise
>> > >whether it is receiving input from a pipe?
>... bunch of non-optimal answers deleted ...
>if [ -t 0 ]

Why, so you prefer YOUR non-optimal answer?
The fellow said "pipe" not terminal.
{class of pipes} + {class of terminals} != {class of files}
Maybe he SHOULD have asked about terminals instead?
If so, he may be in trouble, because it's not at all clear that
"terminal" is a well-defined notion in our modern environments,
or if you do figure out a definition that it would fit his needs.
(Suppose, e.g., you are piping through a pair of terminals that
have been put into a transparent transmission mode.)

peter@ficc.uu.net (Peter da Silva) (03/08/90)

> >> > >Is there any way of getting a Shell script (C or Bourne) to recognise
> >> > >whether it is receiving input from a pipe?
> >... bunch of non-optimal answers deleted ...
> >if [ -t 0 ]
> 
> Why, so you prefer YOUR non-optimal answer?

Because it produces the same result with less overhead. I can't think of
a way to tell if input is from a pipe *from the shell using standard
programs*. In practice, though, this question usually means "How do I tell
if input is interactive or not".
-- 
 _--_|\  `-_-' Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
/      \  'U`
\_.--._/
      v