Obeying a command conditionally on STDIN being nonempty

Obeying a command conditionally on STDIN being nonempty

Post by Chris Thomps » Tue, 23 Mar 1999 04:00:00



There are various situations in which one wants to crank up later parts
of a pipeline only if the earlier parts produce any output. The sort of
situation I have in mind is

  some_command some_arguments 2>&1 | mailx -s "Output of some_command" fall_guy

where one wants no message to be sent in the (common) case when some_command
generates no output. The solution ought to be along the lines of

  some_command some_arguments 2>&1 | \
   obey_if_stdin_nonempty 'mailx -s "Output of some_command" fall_guy'

where your task for today is to implement obey_if_stdin_nonempty.

It's easy enough to write a C or Perl program to do this (though not so easy
to have obey_if_stdin_nonempty actually excise itself from the pipeline
after it has fired up its target command). But I feel there really ought
to be a simple way to do this by using, or misusing, something out of the
standard Unix toolbox. Any thoughts?

Chris Thompson

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by Ken Pizzi » Tue, 23 Mar 1999 04:00:00



Quote:>There are various situations in which one wants to crank up later parts
>of a pipeline only if the earlier parts produce any output. The sort of
>situation I have in mind is

>  some_command some_arguments 2>&1 | mailx -s "Output of some_command" fall_guy
...

>It's easy enough to write a C or Perl program to do this (though not so easy
>to have obey_if_stdin_nonempty actually excise itself from the pipeline
>after it has fired up its target command). But I feel there really ought
>to be a simple way to do this by using, or misusing, something out of the
>standard Unix toolbox.

The most prevalant way I'm aware of is to use a temporary file:
   some_command some_arguments 2>&1 >/tmp/tmp.$$
   test -s /tmp/tmp.$$ &&
     mailx -s "Output of some_command" fall_guy </tmp/tmp.$$
   rm -f /tmp/tmp.$$

You can also mimic the C program you seem to be alluding to:
   some_command some_arguments |
     if read line; then
        (printf "%s\n" "$line"; exec cat) |
        mailx -s "Output of some_command" fall_guy </tmp/tmp.$$
     fi

                --Ken Pizzini

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by Jan Wuyt » Wed, 24 Mar 1999 04:00:00



>...

>   some_command some_arguments 2>&1 | \
>    obey_if_stdin_nonempty 'mailx -s "Output of some_command" fall_guy'

> where your task for today is to implement obey_if_stdin_nonempty.

How about defining 'obey_if_stdin_nonempty' as...

#!/bin/sh
cat >/tmp/$$
if [ -s /tmp/$$ ]
then

fi
rm -f /tmp/$$

Also note that your command:

some_command some_arguments 2>&1 | \
    obey_if_stdin_nonempty 'mailx -s "Output of some_command" fall_guy'

will not send stderr down the pipe!

You should do:

(some_command some_arguments 2>&1) | \
    obey_if_stdin_nonempty 'mailx -s "Output of some_command" fall_guy'

Cheers
--

      Jan Wuyts

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by Ken Pizzi » Wed, 24 Mar 1999 04:00:00



>some_command some_arguments 2>&1 | \
>    obey_if_stdin_nonempty 'mailx -s "Output of some_command" fall_guy'

>will not send stderr down the pipe!

Yes it will.  Prove it to yourself with:
   ls -l no_such_file 2>&1 | od -c

                --Ken Pizzini

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by Chris Thomps » Wed, 24 Mar 1999 04:00:00





>>There are various situations in which one wants to crank up later parts
>>of a pipeline only if the earlier parts produce any output. The sort of
>>situation I have in mind is

>>  some_command some_arguments 2>&1 | mailx -s "Output of some_command" fall_guy
>...

>>It's easy enough to write a C or Perl program to do this (though not so easy
>>to have obey_if_stdin_nonempty actually excise itself from the pipeline
>>after it has fired up its target command). But I feel there really ought
>>to be a simple way to do this by using, or misusing, something out of the
>>standard Unix toolbox.

>The most prevalant way I'm aware of is to use a temporary file:
>   some_command some_arguments 2>&1 >/tmp/tmp.$$
>   test -s /tmp/tmp.$$ &&
>     mailx -s "Output of some_command" fall_guy </tmp/tmp.$$
>   rm -f /tmp/tmp.$$

Yes, I ought to have ruled that out in my original posting! [It's essentially
what cron does with the output of a job, of course.] Assume that although
the output of some_command is usually empty, it's sometimes very large!
[Although in that case one wouldn't want to mail the whole thing anyway,
of course. Maybe this is getting pointlessly perfectionist...]

Quote:>You can also mimic the C program you seem to be alluding to:
>   some_command some_arguments |
>     if read line; then
>        (printf "%s\n" "$line"; exec cat) |
>        mailx -s "Output of some_command" fall_guy </tmp/tmp.$$
>     fi

Nicer... :-) The C program would have read one byte, of course...

[I assume the "</tmp/tmp.$$" is an accidental transcription from
the other example.]

Chris Thompson

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by Ken Pizzi » Thu, 25 Mar 1999 04:00:00



Quote:>>You can also mimic the C program you seem to be alluding to:
>>   some_command some_arguments |
>>     if read line; then
>>        (printf "%s\n" "$line"; exec cat) |
>>        mailx -s "Output of some_command" fall_guy </tmp/tmp.$$
>>     fi

>Nicer... :-) The C program would have read one byte, of course...

>[I assume the "</tmp/tmp.$$" is an accidental transcription from
>the other example.]

Ooops!  Yes, that was a "copy-and-paste error".

                --Ken Pizzini

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by John DuBo » Wed, 31 Mar 1999 04:00:00



Quote:>There are various situations in which one wants to crank up later parts
>of a pipeline only if the earlier parts produce any output. The sort of
>situation I have in mind is

>  some_command some_arguments 2>&1 | mailx -s "Output of some_command" fall_guy
....

>It's easy enough to write a C or Perl program to do this (though not so easy
>to have obey_if_stdin_nonempty actually excise itself from the pipeline
>after it has fired up its target command).

A utility that does excise itself from the pipeline:
ftp://ftp.armory.com./pub/source/iirun.tar.gz

For your example, you'd do:
some_command some_arguments 2>&1 | iirun mailx -s "Output of some_command" fall_guy



>Nicer... :-) The C program would have read one byte, of course...

Not if you can use select() and fstat() on a pipe, which I believe is
near-universal these days...

        John
--

 
 
 

Obeying a command conditionally on STDIN being nonempty

Post by Chris Thomps » Wed, 31 Mar 1999 04:00:00





>>There are various situations in which one wants to crank up later parts
>>of a pipeline only if the earlier parts produce any output. The sort of
>>situation I have in mind is

>>  some_command some_arguments 2>&1 | mailx -s "Output of some_command" fall_guy
>....

>>It's easy enough to write a C or Perl program to do this (though not so easy
>>to have obey_if_stdin_nonempty actually excise itself from the pipeline
>>after it has fired up its target command).

>A utility that does excise itself from the pipeline:
>ftp://ftp.armory.com./pub/source/iirun.tar.gz

>For your example, you'd do:
>some_command some_arguments 2>&1 | iirun mailx -s "Output of some_command" fall_guy



>>Nicer... :-) The C program would have read one byte, of course...

>Not if you can use select() and fstat() on a pipe, which I believe is
>near-universal these days...

Thanks for the input. Indeed, that is probably the most portable way of
doing it. I ended up using poll(2), which can distinguish data from EOF
without the fstat(), but that's a bit Solaris2-specific. [Both methods
have problems distinguishing zero-length messages from "real" end-of-file,
but that may be inevitable with pipes-implemented-as-streams.]

Apologies for this being off-topic for comp.unix.shell. I still have an
interest in neat solutions using the standard Unix toolkit.

Chris Thompson
Email: cet1 [at] cam.ac.uk