[comp.unix.wizards] shell stderr in popen

tw@foobar.UUCP (Tom Walsh) (08/04/87)

  hi, sortof like the scanf() contest...
  i have a need to use popen(command, "r").  if command is not
  found, i would like to dispose quietly of the shell's complaint:
  sh: command: not found
  the stderr of the command itself can be handled ala:
  popen("/usr/bin/mynewcommand -flags 2> /dev/null", "r");
  but if "mynewcommand" isn't around, the shell's stderr still
  gets put on the *real* stderr.

  question:
   is there an easier way than:
    .
    .
    .
    realerr = dup(stderr);
    freopen("/dev/null", "w", stderr);
    popen();
    do_stuff();
    pclose();
    fclose(stderr);
    dup2(realerr, stderr);
    .
    .
    .
  to get rid of the shell's stderr????

-tw (Tom Walsh, (503)696-7105, Intel Corp; Hillsboro OR)
 ...tektronix!psu-cs!omosys!             \
 ...seismo!vrdxhq!verdix!omepd!littlei!   \
 ...intelisc!                              >foobar!tw
 ...inteloa!                              /
 ...omepd!littlei!                       /

ugbinns@sunybcs.uucp (Leonard Binns) (08/07/87)

In article <124@foobar.UUCP> tw@foobar.UUCP (Tom Walsh) writes:
>
>  hi, sortof like the scanf() contest...

Oh no!  :-)

>  i have a need to use popen(command, "r").  if command is not
>  found, i would like to dispose quietly of the shell's complaint:
>  sh: command: not found
>  the stderr of the command itself can be handled ala:
>  popen("/usr/bin/mynewcommand -flags 2> /dev/null", "r");
>
>  question:
>   is there an easier way than:

Did you ever try:
	popen("/usr/bin/mynewcommand -flags 2>& /dev/null", "r");
					     ^^^
I think that should do the trick.

	Len Binns
	ugbinns@marvin.UUCP

dce@mips.UUCP (David Elliott) (08/07/87)

In article <4511@sunybcs.UUCP> ugbinns@marvin.UUCP (Leonard Binns) writes:
>In article <124@foobar.UUCP> tw@foobar.UUCP (Tom Walsh) writes:
>
>>  i have a need to use popen(command, "r").  if command is not
>>  found, i would like to dispose quietly of the shell's complaint:
>>  sh: command: not found
>>  the stderr of the command itself can be handled ala:
>>  popen("/usr/bin/mynewcommand -flags 2> /dev/null", "r");
>>
>>  question:
>>   is there an easier way than:
>
>Did you ever try:
>	popen("/usr/bin/mynewcommand -flags 2>& /dev/null", "r");
>					     ^^^
>I think that should do the trick.

Why should it do the trick? It isn't even valid shell syntax!
Remember that popen() uses /bin/sh, not your SHELL (and if AT&T
changes this, I QUIT!). The >& is used in the sequence

	m>&n

which says "make file descriptor m a duplicate of file descriptor
n". The sequence 2>& /dev/null results in "/dev/null: bad file
number".

Anyway, the easiest way to do this is

	popen("( /usr/bin/bin/mynewcommand -flags ) 2>/dev/null", "r");

The sequence

	( command )

runs the command in a subshell, so all redirection done outside of
the parenthesis applies to the subshell.

This is also useful in cases like:

	( cat file1 ; echo separator ; cat file2 ) | filter

-- 
David Elliott		{decvax,ucbvax,ihnp4}!decwrl!mips!dce

chris@mimsy.UUCP (Chris Torek) (08/09/87)

>In article <124@foobar.UUCP> tw@foobar.UUCP (Tom Walsh) writes:
>>[Using] popen(command, "r") ... i would like to dispose quietly of
>>the shell's complaint:
>>  sh: command: not found

In article <4511@sunybcs.UUCP> ugbinns@sunybcs.uucp (Leonard Binns) writes:
>Did you ever try:
>	popen("/usr/bin/mynewcommand -flags 2>& /dev/null", "r");

This will not do it.  (For one thing, it is syntactically invalid.)
The shell prints `sh: <x>: not found' to the *shell's* standard
error output, before any redirection.  There are several possible
solutions, but the easiest is to add one level of indirection:

	(void) sprintf(expandcmd, "sh -c '%s' 2>/dev/null", command);
	iop = popen(expandcmd, "r");

Note that this assumes `command' has no single quotes embedded in
it.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

rayan@utegc.UUCP (08/10/87)

In article <7928@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
# >In article <124@foobar.UUCP> tw@foobar.UUCP (Tom Walsh) writes:
# >> ... i would like to dispose quietly of the shell's complaint:
# >>  sh: command: not found
#
# In article <4511@sunybcs.UUCP> ugbinns@sunybcs.uucp (Leonard Binns) writes:
# >	popen("/usr/bin/mynewcommand -flags 2>& /dev/null", "r");
# 
# This will not do it. ... [try:]
# 
# 	(void) sprintf(expandcmd, "sh -c '%s' 2>/dev/null", command);
# 	iop = popen(expandcmd, "r");

Seems too expensive. Try

	popen("exec 2> /dev/null ; /usr/bin/mynewcommand -flags", "r");

exec with no command does wonderful things to your shell. It is documented
too, on BSD flavours at least. Also, it is built-in (obviously) so there
is very little overhead involved.

rayan
-- 
Rayan Zachariassen
AI group, University of Toronto

chris@mimsy.UUCP (Chris Torek) (08/10/87)

>In article <7928@mimsy.UUCP> I suggest:
># 	(void) sprintf(expandcmd, "sh -c '%s' 2>/dev/null", command);
># 	iop = popen(expandcmd, "r");

In article <8708100615.AA06203@ephemeral.ai.toronto.edu> rayan@utegc.UUCP
writes:
>Seems too expensive. Try
>
>	popen("exec 2> /dev/null ; /usr/bin/mynewcommand -flags", "r");

This is a good idea.  Unfortunately, it does not work; the shell has
already set its own standard error to another descriptor, so that it
can still print errors.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

jgy@hropus.UUCP (John Young) (08/11/87)

> >In article <7928@mimsy.UUCP> I suggest:
> ># 	(void) sprintf(expandcmd, "sh -c '%s' 2>/dev/null", command);
> ># 	iop = popen(expandcmd, "r");
> 
> In article <8708100615.AA06203@ephemeral.ai.toronto.edu> rayan@utegc.UUCP
> writes:
> >Seems too expensive. Try
> >
> >	popen("exec 2> /dev/null ; /usr/bin/mynewcommand -flags", "r");
> 
> This is a good idea.  Unfortunately, it does not work; the shell has
> already set its own standard error to another descriptor, so that it
> can still print errors.
> -- 
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
> Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris
> 

It has always worked for me on System V systems.

rayan@utegc.UUCP (08/11/87)

>In article <7928@mimsy.UUCP> Chris suggests:
># 	(void) sprintf(expandcmd, "sh -c '%s' 2>/dev/null", command);
># 	iop = popen(expandcmd, "r");

In article <8708100615.AA06203@ephemeral.ai.toronto.edu> I write:
>Seems too expensive. Try
>
>	popen("exec 2> /dev/null ; /usr/bin/mynewcommand -flags", "r");

In article <7932@mimsy.UUCP> Chris replies:
# This is a good idea.  Unfortunately, it does not work; the shell has
# already set its own standard error to another descriptor, so that it
# can still print errors.

Before posting my suggestion above, I tried it out. I'm on a SunOS 3.4 box,
and using exec as shown did indeed get rid of the ": not found" message.
But Chris usually knows what he's talking about (too...), so I just tried it
on 4.3bsd. There his admonition holds true. Therefore I conclude that early
v7-based sh's (as in 4.3bsd) require something like:

1.	popen("( /usr/bin/mynewcommand -flags ) 2> /dev/null", "r");

while sysV-based sh's (as in SunOS) will work with:

2.	popen("exec 2> /dev/null ; /usr/bin/mynewcommand -flags", "r");

Note that method 1. is less overhead (one less path search and exec), and
less problematic vis-a-vis quoting, than the original suggestion at the top
of this message.

I thought of specifying the fd that the 4.3 sh dup's stderr to, instead of '2'.
Unfortunately, that is fd 11, and only single digits may be used to specify
the fd for a redirection. I'm glad this feature of juggling the fd's around
was removed in sysV (presumably).

Live and learn.

rayan
-- 
Rayan Zachariassen
AI group, University of Toronto

allbery@ncoast.UUCP (Brandon Allbery) (08/13/87)

As quoted from <124@foobar.UUCP> by tw@foobar.UUCP (Tom Walsh):
+---------------
| 
|   hi, sortof like the scanf() contest...
|   i have a need to use popen(command, "r").  if command is not
|   found, i would like to dispose quietly of the shell's complaint:
|   sh: command: not found
|   the stderr of the command itself can be handled ala:
|   popen("/usr/bin/mynewcommand -flags 2> /dev/null", "r");
|   but if "mynewcommand" isn't around, the shell's stderr still
|   gets put on the *real* stderr.
+---------------

popen("exec 2> /dev/null; /usr/bin/mynewcommand -flags", "r");
-- 
 Brandon S. Allbery, moderator of comp.sources.misc and comp.binaries.ibm.pc
  {{harvard,mit-eddie}!necntc,well!hoptoad,sun!mandrill!hal}!ncoast!allbery
ARPA: necntc!ncoast!allbery@harvard.harvard.edu  Fido: 157/502  MCI: BALLBERY
   <<ncoast Public Access UNIX: +1 216 781 6201 24hrs. 300/1200/2400 baud>>
** Site "cwruecmp" is changing its name to "mandrill".  Please re-address **
*** all mail to ncoast to pass through "mandrill" instead of "cwruecmp". ***

ggs@ulysses.homer.nj.att.com (Griff Smith) (08/16/87)

chris@mimsy.UUCP:
> 	(void) sprintf(expandcmd, "sh -c '%s' 2>/dev/null", command);
> 	iop = popen(expandcmd, "r");
> 
rayan@utegc.UUCP:
>Seems too expensive. Try
>
>	popen("exec 2> /dev/null ; /usr/bin/mynewcommand -flags", "r");
> 

How about:
	popen("(/usr/bin/mynewcommand -flags) 2> /dev/null", "r");

Only costs an exra fork, no exec, not much extra typing.  Did I miss something?
-- 
Griff Smith	AT&T (Bell Laboratories), Murray Hill
Phone:		1-201-582-7736
UUCP:		{allegra|ihnp4}!ulysses!ggs
Internet:	ggs@ulysses.uucp