pipe both, stdout and stderr in the fish shell - fish

I know this has been an issue for a while and I found a lot of discussion about it, however I didn't get which would be finally a way to get it done: pipe both, stdout and stderr. In bash, this would be simply:
cmd 2>&1 | cmd2

That syntax works in fish too. A demo:
$ function cmd1
echo "this is stdout"
echo "this is stderr" >&2
end
$ function cmd2
rev
end
$ cmd1 | cmd2
this is stderr
tuodts si siht
$ cmd1 &| cmd2
rredts si siht
tuodts si siht
Docs: https://fishshell.com/docs/current/language.html#redirects

There's also a handy shortcut, per these docs
&>
Here's the relevant quote (emphasis and white space, mine):
As a convenience, the redirection &> can be used to direct both stdout
and stderr to the same destination. For example:
echo hello &> all_output.txt
redirects both stdout and stderr to the file
all_output.txt. This is equivalent to echo hello > all_output.txt 2>&1.

Related

echo shows command I want to execute

First let me explain that I have very little expertise with bash scripting. I only use it for very simple applications.
My script is used to generate a grep command.
I use the echo command as an interim debug tool. I figure that if I can get the echo command to show the command I want to execute, all I have to do is remove the echo and the quotes and the command inside the echo should do what I want.
Here is my script (called grepper3.sh). Again, I am not an expert at this:
#!/bin/bash
echo "what should I grep?"
read this
echo "grep -Ri \"$this\" > \"$this\""
Here is what happens when I execute:
master#master-Latitude-E6440:~$ ./grepper3.sh
what should I grep?
all that
grep -Ri "all that" > "all that"
The grep command being echoed by the code is exactly what I want. But when I remove the echo and the surrounding double quotes:
was: echo "grep -Ri \"$this\" > \"$this\""
changed to: grep -Ri \"$this\" > \"$this\"
I get this:
master#master-Latitude-E6440:~$ ./grepper3.sh
what should I grep?
all that
./grepper3.sh: line 5: \"$this\": ambiguous redirect
I'm guessing that there is a simple fix, but I can't figure it out.
You can add . to recursive search.
#!/bin/bash
echo "what should I grep?"
read this
grep -Ri $this > $this .
All you need to to is to change the quotation marks to backticks.
Your new code would be:
#!/bin/bash
echo "what should I grep?"
read this
echo `grep -Ri \"$this\" > \"$this\"`
Here is what I finally got to work. Thanks for all of your help!
#!/bin/bash
echo "what should I grep?"
read this
DEST="/home/master/results/$this"
grep -Ri "$this" > "$DEST"

Msys: how to keep STDERR on the screen and at the same time copy both STDOUT and STDERR to files

I would like to be able to
Display STDERR on the screen
Copy STDOUT and STDERR in files (and if possible in the same file)
For information, I am using Msys to do that.
.
After doing some research on the SO, I have tried to use something like
<my command> > >(tee stdout.log) 2> >(tee stderr.log)
Bu I got the following error:
sh: syntax error near unexpected token `>'
.
Any idea on how to do that?
There might be no direct solution in Msys but the >(tee ... ) solution works fine in *Nix, OSX, and probably Cygwin.
The workaround is to grep all the errors and warnings we want to keep them on the screen.
I have successfully used the following command for a makefile to compile C code:
make 2>&1 | tee make.log | grep -E "(([Ee]rror|warning|make):|In function|undefined)"
I have a simple script (test.sh) that generates STDOUT and STDERR:
#!/bin/bash
echo hello
rm something
exit
Then, to do what you want execute with the following:
./test.sh > stdout.log 2> >(tee stderr.log >&2)
You'll get the STDERR on the screen, and two separated log files with STDERR and STDOUT. I used part of the answer given here
Note that I am assuming you don't have a file called something on the current directory :)
If you want both STDOUT and STDERR to go to the same file, use the -a option on tee:
./test.sh > std.log 2> >(tee -a std.log >&2)

Logging stdout and stderr separately and together simultaneously

I have a specific problem I'd like to solve and I'm running system through perl which I think runs in bash:
Show stdout and stderr in both.log. Add "done" if it finished.
Append stderr in stderr.log
Don't print out to terminal, except the original command and "done" if the command finished.
So once we combine stdout and stderr, can we separate them again? OR can we first capture stderr and then combine it with stdout after?
bash: system("((" . $cmd . " 2>&1 1>&3 | tee -a stderr.log) 3>&1) > both.log; echo done | tee -a both.log"
Even though we use tee for stderr.log it doesn't tee the error output to the terminal (which is what I want). I don't completely understand how it works, but I guess the tee causes it to go to the log file and also to the next file descriptor equation.
Bonus
I found this here in the comments: http://wiki.bash-hackers.org/howto/redirection_tutorial
This can be used to do the same thing, but all output is also teed to terminal (It doesn't print "done").
bash:
(($command 2>&1 1>&3 | tee stderr.log) 3>&1 ) | tee both.log
Using Perl 5.14.1.
tcsh alone would not suffice here. It does not support redirecting stderr without stdout.
Use another shell or a designated script.
More here.
UPDATE:
Can this be ported to tcsh?
No. tcsh does not support redirecting stderr without stdout.

How to capture error message from prompt - shell or perl

I am trying to capture the output of a command. It works fine if the command executes. However when there is an error, i am unable to capture what gets displayed in commandline
Eg.
$ out=`/opt/torque/bin/qsub submitscript`
qsub: Unauthorized Request MSG=group ACL is not satisfied: user abc#xyz.org, queue home
$ echo $out
$
I want $out to have the message
Thanks!
Errors are on stderr, so you need to redirect them into stdout so the backticks will capture it:
out=`/opt/torque/bin/qsub submitscript 2>&1`
if [ $? -gt 0 ] ; then
# By convention, this is sent to stderr, but if you need it on
# stdout, just remove the >&2 redirection
echo "Error: $out" >&2
else
echo "Success: $out"
fi
You should test the exit status of the command to figure out what the output represents (one way shown). It is similar for perl, slightly different syntax of course.
Have you tried doing it like this
$ out=`/opt/torque/bin/qsub submitscript 2>&1 > /dev/null`
$ echo $out

how to trim wipe output with sed?

i want to trim an output of wipe command with sed.
i try to use this one:
wipe -vx7 /dev/sdb 2>&1 | sed -u 's/.*\ \([0-9]\+\).*/\1/g'
but it don't work for some reason.
when i use echo & sed to print the output of wipe command it works!
echo "/dev/sdb: 10%" | sed -u 's/.*\ \([0-9]\+\).*/\1/g'
what i'm doing wrong?
Thanks!
That looks like a progress indicator. They are often output directly to the tty instead of to stdout or stderr. You may be able to use the expect script called unbuffer (source) or some other method to create a pseudo tty. Be aware that there will probably be more junk such as \r, etc., that you may need to filter out.
Demonstration:
$ cat foo
#!/bin/sh
echo hello > /dev/tty
$ a=$(./foo)
hello
$ echo $a
$ a=$(unbuffer ./foo)
$ echo $a
hello