[comp.sources.misc] v06i031: redir - redirect stdout and stderr separately

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (02/04/89)

Posting-number: Volume 6, Issue 31
Submitted-by: bobg+@andrew.cmu.edu
Archive-name: redir

This is redir, a simple Unix program for csh(1) users who are tired of being
sneered at by their sh(1)-using brothers because their shell can't separate
stdout from stderr.  Redir will exec a program you name, redirecting the
standard output and/or the standard error (or neither) according to redir's
options.  Previously, the only good way of separating stdout from stderr in csh
was something like

        (command > stdout-destination) >& stderr-destination

which stinks.  Suppose you wanted to pipe command A through command B,
collecting the stderr of A in A.err and the stderr of B in B.err, while
displaying the stdout of B?  What would you do then, huh?  Probably something
awful that looks like this:

        (A | (B > /dev/tyy) >& B.err) >& A.err

I'm not even sure that would work.  I am sure that this works:

        redir -e A.err A | redir -e B.err B

Well, here it is.

----- Not this line -----
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#               "End of shell archive."
# Contents:  README Makefile redir.c redir.doc
# Wrapped by bobg@ephrata.andrew.cmu.edu on Sun Jan 29 19:02:42 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(893 characters\)
sed "s/^X//" >README <<'END_OF_README'
XRedir is a simple utility which remedies a problem in csh(1);
Xnamely, that you can't redirect stdout and stderr separately,
Xas you can in sh(1), unless you want to do something ugly like
X
X       (command > stdout) >& stderr
X
XRedir will execute the command you name, with stdout and
Xstderr redirected according to the options you supply to redir.
XThe file redir.doc gives the usage of this program.
X
XTo compile this program, type "make redir".  To install this
Xprogram on your system, modify the Makefile so that the
Xvariables BIN and DOC are defined to be the pathnames
Xof the directories to hold the binary file "redir" and the
Xdocumentation file "redir.doc," respectively, then type
X"make install".
X
XThis software exists in the public domain.  Absolutely no
Xrestrictions on its usage, modification or distribution
Xexist.  No guarantees are made concerning the proper
Xfunctioning of this software.
END_OF_README
if test 893 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(350 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
XOPTIMIZE = -O
XDEBUG =
XINCLUDES =
XPROFILE =
XLIBS =
XCFLAGS = $(OPTIMIZE) $(DEBUG) $(INCLUDES) $(PROFILE)
XCC = cc
XBIN =
XDOC =
X
XTARGET = redir
X
Xredir: redir.c
X       $(CC) $(CFLAGS) -o redir redir.c
X
Xtest: $(TARGET)
X
Xinstall: $(TARGET)
X       cp $(TARGET) $(BIN)
X       -strip $(BIN)/$(TARGET)
X       cp redir.doc $(DOC)
X
Xclean:
X       -rm -f *.BAK *.CKP *.o a.out gmon.out $(TARGET)
END_OF_Makefile
if test 350 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f redir.c -a "${1}" != "-c" ; then
  echo shar: Will not over-write existing file \"redir.c\"
else
echo shar: Extracting \"redir.c\" \(3851 characters\)
sed "s/^X//" >redir.c <<'END_OF_redir.c'
X/* redir
X * a program to execute a command, redirecting stdout and stderr separately,
X * a feature available in sh but not csh.
X *
X * THIS SOFTWARE EXISTS IN THE PUBLIC DOMAIN.  ABSOLUTELY NO
X * RESTRICTIONS ON ITS USAGE, MODIFICATION OR DISTRIBUTION
X * EXIST.  NO GUARANTEES ARE MADE CONCERNING THE PROPER
X * FUNCTIONING OF THIS SOFTWARE.
X *
X * Usage:
X *
X * redir [options] command-words...
X *
X * where options are
X *  -o file
X *   to redirect stdout to file "file," without clobbering "file" if it exists
X *  -e file
X *   to redirect stderr to file "file," without clobbering "file" if it exists
X *  -O file
X *   to redirect stdout to file "file," clobbering "file" if it exists
X *  -E file
X *   to redirect stderr to file "file," clobbering "file" if it exists
X *  -a
X *   the following redirection option is to append to the named file, as in:
X *    redir -O foo.log -ae foo.err command command-arg1 command-arg2 ...
X *   (stdout (destructively) to foo.log, stderr appended to foo.err.
X *   The -a option doesn't care if the named file exists or not.  This option
X *   must be used twice if you want stdout and stderr both to be appended
X *   to their respective files;
X *    redir -ao foo.log -ae foo.err command ...
X */
X
X#include <stdio.h>
X#include <sys/file.h>
X
X#define USAGESTRING ("Usage: %s [-[a][oeOE] file] ... command-words\n")
X
Xmain(argc, argv)
Xint             argc;
Xchar          **argv;
X{
X    extern int      optind;
X    extern char    *optarg;
X    char           *stderrfile = NULL, *stdoutfile = NULL;
X    int             rstderr = 0, rstdout = 0, cstderr = 0, cstdout = 0, astderr
= 0, astdout = 0, appendopt = 0, c, fd;
X
X    while ((c = getopt(argc, argv, "ao:e:O:E:")) != EOF) {
X       switch (c) {
X           case 'a':
X               if (appendopt) {
X                   fprintf(stderr, USAGESTRING, argv[0]);
X                   exit(1);
X               }
X               ++appendopt;
X               break;
X           case 'e':
X               if (rstderr) {
X                   fprintf(stderr, USAGESTRING, argv[0]);
X                   exit(1);
X               }
X               ++rstderr;
X               stderrfile = optarg;
X               if (appendopt) {
X                   appendopt = 0;
X                   ++astderr;
X               }
X               break;
X           case 'o':
X               if (rstdout) {
X                   fprintf(stderr, USAGESTRING, argv[0]);
X                   exit(1);
X               }
X               ++rstdout;
X               stdoutfile = optarg;
X               if (appendopt) {
X                   appendopt = 0;
X                   ++astdout;
X               }
X               break;
X           case 'E':
X               if (rstderr) {
X                   fprintf(stderr, USAGESTRING, argv[0]);
X                   exit(1);
X               }
X               ++rstderr;
X               ++cstderr;
X               stderrfile = optarg;
X               if (appendopt) {
X                   appendopt = 0;
X                   ++astderr;
X               }
X               break;
X           case 'O':
X               if (rstdout) {
X                   fprintf(stderr, USAGESTRING, argv[0]);
X                   exit(1);
X               }
X               ++rstdout;
X               ++cstdout;
X               stdoutfile = optarg;
X               if (appendopt) {
X                   appendopt = 0;
X                   ++astdout;
X               }
X               break;
X           default:
X               fprintf(stderr, USAGESTRING, argv[0]);
X               exit(1);
X               break;
X       }
X    }
X    if (rstdout) {
X       if ((fd = open(stdoutfile, (astdout ?
X                                   (O_WRONLY | O_APPEND | O_CREAT) :
X                                   (cstdout ?
X                                    (O_WRONLY | O_CREAT | O_TRUNC) :
X                                    (O_WRONLY | O_CREAT | O_EXCL))),
X                      0644)) < 0) {
X           fprintf(stderr,
X                   "%s: couldn't open destination %s for standard output\n",
X                   argv[0], stdoutfile);
X           exit(2);
X       }
X       if (dup2(fd, 1) < 0) {
X           fprintf(stderr,
X                   "%s: couldn't open destination %s for standard output\n",
X                   argv[0], stdoutfile);
X           exit(2);
X       }
X       close(fd);
X    }
X    if (rstderr) {
X       if ((fd = open(stderrfile, (astderr ?
X                                   (O_WRONLY | O_APPEND | O_CREAT) :
X                                   (cstderr ?
X                                    (O_WRONLY | O_CREAT | O_TRUNC) :
X                                    (O_WRONLY | O_CREAT | O_EXCL))),
X                      0644)) < 0) {
X           fprintf(stderr,
X                   "%s: couldn't open destination %s for standard error\n",
X                   argv[0], stderrfile);
X           exit(2);
X       }
X       if (dup2(fd, 2) < 0) {
X           fprintf(stderr,
X                   "%s: couldn't open destination %s for standard error\n",
X                   argv[0], stderrfile);
X           exit(2);
X       }
X       close(fd);
X    }
X    execvp(argv[optind], argv + optind);
X}
END_OF_redir.c
if test 3851 -ne `wc -c <redir.c`; then
    echo shar: \"redir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f redir.doc -a "${1}" != "-c" ; then
  echo shar: Will not over-write existing file \"redir.doc\"
else
echo shar: Extracting \"redir.doc\" \(1658 characters\)
sed "s/^X//" >redir.doc <<'END_OF_redir.doc'
XREDIR(1)
X
XNAME
Xredir - redirect standard output and/or standard error (diagnostic output)
X
XSYNOPSIS
Xredir [-[a][oeOE] file] ... command arg1 arg2 ...
X
XDESCRIPTION
XRedir executes the named command with the given arguments,
Xredirecting the standard output and/or standard input according
Xto the options given.  This program exists to remedy a serious
Xdeficiency in csh(1), namely that csh does not allow stdout
Xand stderr to be redirected separately.  The options are:
X
X-o file        Redirect the standard output of the named command
X       to the file "file", only if "file" does not yet exist.
X-O file        Redirect the standard output of the named command
X       to the file "file", clobbering the existing
X       version of "file" if it exists.
X-e     Redirect the standard error (diagnostic output) of the
X       named command to file "file", only if "file" does not yet exist.
X-E     Redirect the standard error (diagnostic output) of the
X       named command to the file "file", clobbering the existing
X       version of "file" if it exists.
X-ao file       Append the standard output of the named command
X       to the file "file", whether or not "file" exists.
X-ae file       Append the standard error (diagnostic output) of the
X       named command to the file "file", whether or not "file" exists.
X
X-aO and -aE are synonyms for -ao and -ae.
X
XEXAMPLE
XThe following example demonstrates a means for piping the output
Xof sed through ctags and then into awk; errors from ctags will be
Xplaced in the file "errors":
X
X% ... | sed -f sed-script | redir -e errors ctags -x | awk -f awk-script | ...
X
XAUTHOR
XBob Glickstein
X       Information Technology Center
X       Carnegie Mellon University
X       Pittsburgh, PA
X       22-Jan-89
X       ARPAnet: bobg@andrew.cmu.edu
END_OF_redir.doc
if test 1658 -ne `wc -c <redir.doc`; then
    echo shar: \"redir.doc\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0