4

From my understanding, the following should send 'test' on standard error in tcsh:

echo test >&2

However, it instead writes 'test' to a file named 2, and when I look through my history, I find that what actually executed was

echo test > & 2

I'm not sure what layer is inserting those spaces, but can I stop it somehow? If not, I guess I could always use > /dev/stderr instead.

  • echo test >&2 prints to stderr. At least in my bash. – Der Hochstapler May 23 '12 at 14:43
  • 1
    BTW, using > as a shell indicator is pretty confusing in your code snippets in the current context ;) – Der Hochstapler May 23 '12 at 14:44
  • 1
    I assumed bash at first as well but it's tagged tsch. – Dave Forgac May 23 '12 at 14:44
  • 1
    Sorry about the confusion, hopefully my question is more clear now. If I could use bash here, I would, since it works for me. – Nate Parsons May 23 '12 at 15:22
  • Could you quote the redirect? echo test '>&2'? No idea if that works, and don't have tcsh to try it. – kevlar1818 May 23 '12 at 15:36
5

Concerning csh, from http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/:

Along these same lines, you can't direct error messages in csh scripts out stderr as is considered proper. In the Bourne shell, you might say:

echo "$0: cannot find $file" 1>&2

but in the csh, you can't redirect stdout out stderr, so you end up doing something silly like this:

sh -c 'echo "$0: cannot find $file" 1>&2'

I did some quick tries with tcsh, and as suspected it appears to be true for that as well (tcsh is supposed to be fully compatible with csh).


To address your formulated question: it wouldn't matter if you could make tcsh not "insert spaces" since it will not interpret that sequence in the intended way anyway.

6

EDIT:

I didn't see this was tsch. See the "Input/output" section of man tsch for details including this:

Diagnostic output may be directed through a pipe with the standard output. Simply use the form |& rather than just |.

The shell cannot presently redirect diagnostic output without also redirecting standard output, but (command > output-file) >& error-file is often an acceptable workaround. Either output-file or error-file may be /dev/tty to send out-put to the terminal.

  • 2
    Thanks for pointing that out, but I'm not sure it applies. I don't want to redirect the diagnostic output (stderr?) of a process, instead I want the normal output to appear on stdout. – Nate Parsons May 23 '12 at 15:30
  • @drhorrible: It's essentially the same thing. What you're doing is starting the echo process and redirecting its output to stderr. Thus, printing to stderr effectively :) – Der Hochstapler May 24 '12 at 9:35
  • That's not how it seems to work. (echo test > out) >& err writes 'test' to a file called 'out' and creates an empty file 'err' on my machine, at least. – Nate Parsons May 24 '12 at 17:08
  • This is a good way to get STDOUT and STDERR split from a command sending output to both, and send them to files. However, it does not answer the OP's question on how to force STDOUT (which is where echo sends output) to go to STDERR in tcsh. – Randall Dec 26 '17 at 18:42
3

Daniel Andersson's solution is great and will work well if the command you want to run can be run from sh (and, therefore, a subshell, which will be unable to change the directory or modify the environment of your current shell). If you want to convert stdout to stderr but keep the command execution in the current shell, you can use bash only for the stdout-to-stderr redirection, like this:

echo "An error message" | bash -c "cat - 1>&2"

1

I did some experiments with directing to /dev/stderr in a tcsh script. My intention was for the user of the script to be able (also in tcsh) direct standard output and standard error to different places. I found that the script had to look like:

echo 1abc
echo 1ABC >>& /dev/stderr
echo 2abc
echo 2ABC >>& /dev/stderr

If you do not use >>, then in the redirected script output, you lose some of the standard input and/or standard output data. Even so, redirecting the output of the script to a file using a simply >& does not work; it too loses part of standard error (even on bash). You must use a

(SCRIPT >! file.out ) >&! file.err

construct. Here either file or both can be /dev/tty for output to the screen. (If you do not redirect the script output, there is never a problem.)

Note that none of this weirdness occurs if you direct to standard error from inside a program.

Also note that this was on Linux (Ubuntu-MATE LTS 16.04, to be precise). Of course you need at least /dev/stderr to exist for the above to be usable.

After posting this, I found still another issue. If you put a program that writes to standard error after the 1ABC line, then the 1ABC gets lost if you direct standard error to a file. The good news is that in my case, standard error must continue to go to /dev/tty. Gee. :)

To allow for easy modification, and systems without /dev/stderr, I have decided to implement this through the following two header lines

alias stderr echo ; if (-ew /dev/stderr) alias stderr 'echo \!* >> /dev/stderr'
which echo_err > /dev/null ; if !($status) alias stderr echo_err

This allows the user to put a sh script echo_err,

#!/bin/sh
echo $* 1>&2

in the path if bug-free redirection of standard error is really needed (at the expense of two image activations).

Another addition: My post above was about issues in redirecting to /dev/stderr within tcsh. But as long as I am giving aliases, maybe I should also give one for Glen Ragan's solution, which is really very nice if you do not mind an image activation. Define

alias 1to2 '\!* | sh -c "cat 1>&2"'
alias 2to1 '\!* |& cat'

Then you can precede any command for which you want standard output to be redirected to stdout by 1to2. That acts then just like preceding the command by 1>&2 in other shells, including DOS. And it is not buggy in Linux. May as well have a 2to1 too, then. :)

OOPS: A minor flaw in 1to2 above: if the command writes to both standard output and standard error, the order is wrong. The command's standard error stuff ends up before its standard output stuff in the final standard error result. The solution is simple; change | into |&:

alias 1to2 '\!* |& sh -c "cat 1>&2"'

Sorry about that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.