Redirecting Stderr in Csh

Redirecting stderr in csh

csh is significantly more limited than bash when it comes to file redirection. In csh, you can redirect stdout with the usual > operator, you can redirect both stdout and stderr with the >& operator, you can pipe stdout and stderr with the |& operator, but there is no single operator to redirect stderr alone.

The usual workaround is to execute the command in a sub-shell, redirecting stdout in that sub-shell to whatever file you want (/dev/null in this case), and then use the |& operator to redirect stdout and stderr of the sub-shell to the next command in the main shell.

In your case, this means something like:

( command >/dev/null ) |& grep "^[^-]" >&/tmp/fl

Because stdout is redirected to /dev/null inside the sub-shell, the |& operator will end up acting as 2>&1 in bash - since stdout is discarded in the sub-shell, nothing written to stdout will ever reach the pipe.

Redirect stderr to stdout in C shell

The csh shell has never been known for its extensive ability to manipulate file handles in the redirection process.

You can redirect both standard output and error to a file with:

xxx >& filename

but that's not quite what you were after, redirecting standard error to the current standard output.


However, if your underlying operating system exposes the standard output of a process in the file system (as Linux does with /dev/stdout), you can use that method as follows:

xxx >& /dev/stdout

This will force both standard output and standard error to go to the same place as the current standard output, effectively what you have with the bash redirection, 2>&1.

Just keep in mind this isn't a csh feature. If you run on an operating system that doesn't expose standard output as a file, you can't use this method.


However, there is another method. You can combine the two streams into one if you send it to a pipeline with |&, then all you need to do is find a pipeline component that writes its standard input to its standard output. In case you're unaware of such a thing, that's exactly what cat does if you don't give it any arguments. Hence, you can achieve your ends in this specific case with:

xxx |& cat

Of course, there's also nothing stopping you from running bash (assuming it's on the system somewhere) within a csh script to give you the added capabilities. Then you can use the rich redirections of that shell for the more complex cases where csh may struggle.

Let's explore this in more detail. First, create an executable echo_err that will write a string to stderr:

#include <stdio.h>
int main (int argc, char *argv[]) {
fprintf (stderr, "stderr (%s)\n", (argc > 1) ? argv[1] : "?");
return 0;
}

Then a control script test.csh which will show it in action:

#!/usr/bin/csh

ps -ef ; echo ; echo $$ ; echo

echo 'stdout (csh)'
./echo_err csh

bash -c "( echo 'stdout (bash)' ; ./echo_err bash ) 2>&1"

The echo of the PID and ps are simply so you can ensure it's csh running this script. When you run this script with:

./test.csh >test.out 2>test.err

(the initial redirection is set up by bash before csh starts running the script), and examine the out/err files, you see:

test.out:
UID PID PPID TTY STIME COMMAND
pax 5708 5364 cons0 11:31:14 /usr/bin/ps
pax 5364 7364 cons0 11:31:13 /usr/bin/tcsh
pax 7364 1 cons0 10:44:30 /usr/bin/bash

5364

stdout (csh)
stdout (bash)
stderr (bash)

test.err:
stderr (csh)

You can see there that the test.csh process is running in the C shell, and that calling bash from within there gives you the full bash power of redirection.

The 2>&1 in the bash command quite easily lets you redirect standard error to the current standard output (as desired) without prior knowledge of where standard output is currently going.

Is there a way to redirect stderr to a file that works in bash, csh and dash?

On any POSIX-like system, you can use

system("some_program > output.txt 2>&1");

This is because POSIX system is equivalent to calling sh, and POSIX sh supports this kind of redirection. This works independently of whether or not a user opening a terminal on the system will see a Csh prompt.

How to redirect stdout and stderr from csh script

Some simple solutions:

Solution 1:
tee every line you want to log independently, make use of -a switch of tee to append

#!/bin/csh -f    
tar -zxf Python-3.1.1.tgz |& tee -a install.log
cd Python-3.1.1 |& tee -a install.log
./configure |& tee -a install.log
make |& tee -a install.log
make install |& tee -a install.log
cd .. |& tee -a install.log
rm -rf Python-3.1.1 |& tee -a install.log

Solution 2: Add a second script.
For example, rename current install.csh to install_commands,
then add a new install.csh script:

#!/bin/csh -f 
/bin/csh install_commands |& tee install.log


Related Topics



Leave a reply



Submit