Redirecting stderr in csh - linux

I'm executing a program that dumps crash report into STDERR from where I have to filter some necessary information. The problem is that I'm unable to redirect STDERR to STDOUT and PIPE it with grep
command 2>&1 >/dev/null | grep "^[^-]" >& /tmp/fl
Getting error: Ambiguous output redirect.
Same command works under bash terminal.
What should I change to make it work ?

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.

If you dont mind mixing stdout and stderr into the pipe you can use
command |& grep "^[^-]" >& /tmp/fl
Otherwise you can do the hack:
(command >/dev/null) |& grep "^[^-]" >& /tmp/fl
which separates out stdout to null, then piping stdout and stderr just gives
stderr as content.

Related

Shell - pass stderror to second shell script and use it

I would like to execute a shell script, and pass the stderr to the second script. How do I access the stderr from shell1.sh within shell2.sh and read the data to find some text in there?
sh shell1.sh | sh shell2.sh
Simply redirect the stderr to stdout (using 2>&1) before piping it into your other program:
sh shell1.sh 2>&1 | sh shell2.sh
Whatever enters the pipe through the stdout, will exit the pipe through the stdin, so your other program will then see both the original stdout and stderr on the stdin.
If you are not interested in the (original) stdout of the first program, just re-direct it to /dev/null
sh shell1.sh 2>&1 >/dev/null | sh shell2.sh
Note, that there is only a single input channel for a program (stdin), so once you have redirected stderr to stdout there is no way to differentiate between the original stdout and stderr in your piped-to program.
You can use this way to pass only stderr to RHS command while ignoring stdout:
sh shell1.sh 2>&1 >/dev/null | shell2.sh
2>&1 redirects stderr to stdout and >/dev/null redirects stdout to null.

How can I send error output to both stdout and file in bash

If I use this
cmd 2>/var/error.log
Then my error goes to that file but then I can't see on screen.
Is there any way I can simultaneously show it on screen as well as send to file?
This will display both stdout and stderr on the terminal while only sending stderr to err.log:
cmd 2> >(tee err.log >&2)
>(...) is process substitution. (The space between the two consecutive > is essential.) This sends stderr and only stderr to the tee command.
The >&2 causes the error messages remain in stderr. This would be important, for example, if this line occurs inside some script whose stdin or stderr is being redirected. (Hat tip: Chepner.)
cmd 2>&1 | tee /tmp/error.log

How can I retain stderr from nohup?

Nohup redirects stderr to stdout if it points to a terminal. But I want to retain stderr output to the terminal
Is there a way to accomplish that? Is there an alternative?
I don't know if I understood correctly or not.
you mean that you don't want to see the error in terminal?
if yes:
if you want to save the error in file:
nohup command 2> file.txt
if you don't need the errors:
nohup command 2> /dev/null
2 means the error output of command
2> file.txt means write the error output to the file.txt
Just redirect it somewhere else, so it's not the terminal:
nohup bash -c 'echo OUT ; echo ERR >& 2' 2> err
You can redirect the stderr back to stdout instead of to a file to keep the output in the terminal, but it doesn't make much sense: nohup is for situations where the terminal might get lost, in which case you'll lose the stderr.
nohup bash -c 'echo OUT ; echo ERR >& 2' 2> >(cat)

What's the difference between ">/dev/null 2>&1" and "2>/dev/null >&2"

I have a question for redirection.
I always use anycommands > /dev/null 2>&1 when I need not any output. But I have never used anycommands 2> /dev/null >&2
Question: Which one is the best way to expect no outputs? What's the difference between anycommands > /dev/null 2>&1 and anycommands 2> /dev/null >&2
case#1:(echo stdout;echo stderr>&2) >/dev/null 2>&1
stdout(1) is replaced by an fd to /dev/null
stderr(2) descriptor is copied from &1 which now is an fd to /dev/null
result: no output at all
case#2:(echo stdout;echo stderr>&2) 2>&1 >/dev/null
stderr(2) descriptor is copied from &1 which is the default stdout
stdout(1) is replaced by an fd to /dev/null
result: stderr is empty, stdout not shown, stderr on stdout
case#3: (echo stdout; echo stderr >&2) 2> /dev/null >&2
same as case#1, stderr and stdout have switched roles
Effectively, the two are equivalent. cmd > /dev/null 2>&1 connects stdout of the command to /dev/null, and then connects stderr to the same file. cmd 2>/dev/null >&2 connects stderr to /dev/null, and then connects stdout to it. The only difference is in the order in which the two streams are associated with /dev/null, which has no bearing on the status of the command when it is run. In both cases, both streams are redirected to the bit bucket.
If you're using only BASH, use &> to redirect both stdout and stderr. That's the most compact, safe and simple solution.
Regarding your question, the first one is equivalent to &> (it redirects both stdout and stderr to /dev/null.
The second connects stderr to /dev/null and redirects stdout to the new stderr, so it's equivalent to as far as the output is concerned. Just the order of file descriptor operations is reversed.

How to redirect command line outputs to a file, but still show them in the command line?

In tcsh I want to redirect command line outputs to a file, but I still want to show them in the command line.
Did a little bit search that
./MyCommand.sh 2>&1 | tee /tmp/Output.txt
should do the job. But I got an error like:
Ambiguous output redirect
Use of 2>&1 to combine stderr and stdout works only in bash and sh. It does not for csh or tcsh. A work around is suggested at Redirect stdout to stderr in tcsh.
In bash instead of 2>&1 I use |&
Not sure how this plays out for tcsh, but this question isn't currently tagged for it and hoping this helps someone else.
According to this redirect stderr to stdout in c shell you can't do this in csh which tcsh extends which could be related
It isn't clear from the question if you want to redirect stdout only, or stdout and stderr.
Using | will redirect stdout to tee (which outputs it to a file and to terminal), leaving stderr untouched (so it only goes to terminal):
./MyCommand.sh | tee /tmp/Output.txt
Using |& will "merge" stdout and stderr, and tee will redirect both to file and to terminal:
./MyCommand.sh |& tee /tmp/Output.txt

Resources