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
Python Read Linux Memory Process Error (/Proc/$Pid/Mem)
How to Build an If Condition in Shell to Check Whether Curl Succeeded
Use Sed to Delete Certain Lines Using an Index with the Line Numbers to Delete
How to Disassemble a System Call
Does Not Work to Execute Command in Double Brackets in Bash
How to Subtract a Year from a Date Stored in a Variable in Shell Script
Linux Diff Get Only Line Number in the Output
How to Prevent Matlab Printing False Space and Use Wrong Fonts
Icudt Error While Installing Stringi Package from R in Linux Offline
Start X86_64 Code on X86 (32Bit) Linux, Running on X86_64 Cpu
Tomcat6 -> How to Put a Project into the Root Folder
How to Catch Stdout Stream in Ffmpeg Then Pipe It to V4L2Loopback
Nasm: How to Create/Handle Basic Bmp File Using Intel 64 Bit Assembly