76

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
Paolo
  • 21,270
  • 6
  • 38
  • 69
zdd
  • 8,258
  • 8
  • 46
  • 75

6 Answers6

96

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.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 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. – mdiehl13 Aug 04 '15 at 21:19
  • @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. – paxdiablo Aug 05 '15 at 01:16
  • `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. – esmit Aug 03 '17 at 17:51
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
mdiehl13
  • 472
  • 6
  • 19
bioffe
  • 6,283
  • 3
  • 50
  • 65
  • 1
    @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. – paxdiablo Jul 03 '14 at 14:51
  • 2
    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. – chris Jul 03 '14 at 19:30
  • @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. – paxdiablo Jul 09 '14 at 03:49
  • 1
    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". ... **smh** – Trevor Boyd Smith Sep 23 '20 at 16:46
41

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.

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
Chris
  • 613
  • 6
  • 7
5
   xxx >& filename

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

  xxx | & tee ./logfile
Ryan P
  • 201
  • 2
  • 2
4

What about just

xxx >& /dev/stdout

???

ChPortos
  • 75
  • 1
  • 4
  • 3
    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. – Andre Miller Nov 07 '14 at 15:02
-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.

Rob
  • 9