Redirect stderr to stdout in C shell
Asked Answered
C

6

78

When I run the following command in csh, I got nothing, but it works in bash. Is there any equivalent in csh which can redirect the standard error to standard out?

somecommand 2>&1
Callen answered 5/12, 2012 at 9:45 Comment(4)
CSH is dangerous. Try to shift to bash,zsh faqs.org/faqs/unix-faq/shell/csh-whynotMoitoso
@SSHegde what do you mean by "dangerous"?Deejay
@Geza: Please refer to the link which i mentioned in the comment. That explains why.Moitoso
@SSHegde I wish I could star your link to 'csh-whynot'Alanson
H
98

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.

Hisakohisbe answered 5/12, 2012 at 9:49 Comment(3)
Hi, this can be done with csh by modifying bioffe's response a little. What you are wanting is to combine the stderr and stdout streams and NOT into a file. So do 'xxx |& tee /dev/null' and this will have the effect of combining the streams, sending them to a fake file, BUT ALSO sending both to STDOUT on the screen (or wherever you are using stdout). Please update this answer with this option.Vertebra
@mdiehl13, actually, that's a good point and not one I'd considered. However, I'm not sure tee is the right tool for the job. Sending the data via tee to both standard output and /dev/null is no different to sending the data via cat to just standard output. So I updated it with that option, but thanks for the info, it helped a lot.Hisakohisbe
cmd >& /dev/stderr actually totally screwed up my NoMachine session, even though the command was on a remote system from that session. I had upvoted this answer in the past, so presumably it worked in the past, but I am offering this second opinion to beware.Prospector
W
44

I object the above answer and provide my own. csh DOES have this capability and here is how it's done:

xxx |& some_exec # will pipe merged output to your some_exec 

or

xxx |& cat > filename

or if you just want it to merge streams (to stdout) and not redirect to a file or some_exec:

xxx |& tee /dev/null
Weighted answered 25/1, 2014 at 1:4 Comment(4)
@chris, this allows you to send stdout and stderr to the same place but it does not allow you to pipe the standard error to the current standard output. So by all means vote it up, just be aware it doesn't answer the question. What the OP asked for cannot be done with csh, except using the trickery of temporarily calling a bash shell.Hisakohisbe
While there is no exact equivalent in csh, your answer only covers the use case when you want to redirect both stdout and stderr into a file. This answer also demonstrates how to redirect them into a pipe.Etalon
@chris, the question called for a way to direct stderr to the current stdout, not how to direct them both to a brand new location (whether file or pipe). The latter can be done with either the first part of my answer or this answer but there is no way for csh to do the former. If you read the second part of my answer (temporarily calling bash from csh, and now expanded with a concrete example to hopefully clarify), that does it just fine.Hisakohisbe
unbelievably... this solution is the "best" solution for csh. p.s. i can't believe it but... the solution for "how to merge stderr with stdout" via tee /dev/null is the "best". ... smhAlanson
S
42

As paxdiablo said you can use >& to redirect both stdout and stderr. However if you want them separated you can use the following:

(command > stdoutfile) >& stderrfile

...as indicated the above will redirect stdout to stdoutfile and stderr to stderrfile.

Sweetandsour answered 23/1, 2014 at 16:5 Comment(3)
This answer should have more votes IMHO. Is there some negative side effect i don't see?Dispermous
This is the correct answer in my opinion.. the other accepted answer doesn't answer the question!Septima
@Charbel, It doesn't redirect stderr to the current stdout, it redirects both to a new location.Hisakohisbe
P
5
   xxx >& filename

Or do this to see everything on the screen and have it go to your file:

  xxx | & tee ./logfile
Prentice answered 27/2, 2015 at 18:58 Comment(1)
pfctl -t bruteforce -T expire 259200 |& tee | grep -v '0/0 addresses expired.'Sike
N
4

What about just

xxx >& /dev/stdout

???

Nanice answered 7/11, 2014 at 13:24 Comment(1)
This does provide an answer to the question, but it should probably not be presented with the question marks, as it looks like the poster is unsure if this answers the question.Kate
L
-2

I think this is the correct answer for csh.

xxx >/dev/stderr

Note most csh are really tcsh in modern environments:

rmockler> ls -latr /usr/bin/csh

lrwxrwxrwx 1 root root 9 2011-05-03 13:40 /usr/bin/csh -> /bin/tcsh

using a backtick embedded statement to portray this as follows:

echo "`echo 'standard out1'` `echo 'error out1' >/dev/stderr` `echo 'standard out2'`" | tee -a /tmp/test.txt ; cat /tmp/test.txt

if this works for you please bump up to 1. The other suggestions don't work for my csh environment.

Longhair answered 13/2, 2014 at 16:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.