If redirecting STDERR to STDOUT and redirecting STDOUT to a file, why are STDERR messages not showing in the file? - bash

I made a quick little script, test.sh, that looks like the following:
echo "StdErr" > /dev/stderr
echo "StdOut" > /dev/stdout
According to the answers to this SO question, and the Advanced Bash-Scripting Guide, the following should redirect stderr to stdout from the script above:
$ sh /tmp/test.sh 2>&1
And indeed it does:
$ sh /tmp/test.sh 2>&1 |tee file;
$ cat file
StdErr
StdOut
The question that I am wondering is where does the output from stderr go in the following code?
$ sh /tmp/test.sh > file 2>&1
$ cat file
StdOut
I am using GNU bash, version 4.0.24(2)-release.

Your script writes "StdErr" to the file. Then, the next line overwrites the file with "StdOut". You should use >> if you want to append to the file. Since you are redirecting, /dev/stderr and /dev/stdout are regular files, subject to truncation. Try your test again, but this time make file a fifo instead of a regular file.

I'm seeing the output to stderr going to the file, as expected:
$> sh test.sh > file 2>&1
$> cat file
StdErr
StdOut
This is bash 3.2.48.
$> bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)

I have the same issue on RedHat with Bash version GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu). On my Mac with Bash and ZSH both works as expected.
[13:31:05][user#machine: ~/src]$ bash test
1STD ERR
2STD ERR
3STD OUT
4STD OUT
[13:31:40][user#machine: ~/src]$ bash test >> log 2>&1
[13:31:48][user#machine: ~/src]$ cat log
4STD OUT
[13:31:52][user#machine: ~/src]$
[13:32:10][user#machine: ~/src]$ bash test > log 2>&1
[13:32:15][user#machine: ~/src]$ cat log
4STD OUT
[13:32:18][user#machine: ~/src]$

Related

Why does > not redirect output to text file

I run the following command in shell:
sh myscript.sh > test.txt
The output is displayed on shell. I was expecting that the output would be put into test.txt.
The output isn't displayed on the shell, instead it's the STDERR that's displayed on the shell.
If you want both the STDOUT and STDERR to be redirected to the log file, say:
sh myscript.sh > test.txt 2>&1
Since you've tagged the question bash, you could also say:
bash myscript.sh >& test.txt
Printed output maybe be standard error output.
Using following, you can also redirect standard error (file descriptor 2):
sh myscript.sh > test.txt 2>&1
In bash, you can also use following forms:
sh myscript.sh &> test.txt # This is preferred according to bash(1).
sh myscript.sh >& test.txt

how to log all the command output to one single file in bash scripting [duplicate]

This question already has an answer here:
Output bash script into file (without >> )
(1 answer)
Closed 9 years ago.
In gnu/Linux i want to log all the command output to one particular file.
Say in terminal,i am typing
echo "Hi this is a dude"
It should print in the file name specified earlier without using the redirection in every command.
$ script x1
Script started, file is x1
$ echo "Hi this is a dude"
Hi this is a dude
$ echo "done"
done
$ exit
exit
Script done, file is x1
Then, the contents of file x1 are:
Script started on Thu Jun 13 14:51:29 2013
$ echo "Hi this is a dude"
Hi this is a dude
$ echo "done"
done
$ exit
exit
Script done on Thu Jun 13 14:51:52 2013
You can easily edit out your own commands and start/end lines using basic shell scripting (grep -v, especially if your Unix prompt has a distinctive substring pattern)
Commands launched from the shell inherit the file descriptor to use for standard output from the shell. In your typical interactive shell, standard output is the terminal. You can change that by using the exec command:
exec > output.txt
Following that command, the shell itself will write its standard output to a file called output.txt, and any command it spawns will do likewise, unless otherwise redirected. You can always "restore" output to the terminal using
exec > /dev/tty
Note that your shell prompt and text you type at the prompt continue to be displayed on the screen (since the shell writes both of those to standard error, not standard output).
{ command1 ; command2 ; command3 ; } > outfile.txt
Output redirection can be achieved in bash with >: See this link for more info on bash redirection.
You can run any program with ported output and all its output will go to a file, for example:
$ ls > out
$ cat out
Desktop
Documents
Downloads
eclipse
Firefox_wallpaper.png
...
So, if you want to open a new shell session with ported output, just do so!:
$ bash > outfile
will start a new bash session porting all of stdout to that file.
$ bash &> outfile
will port all of stdout AND stderr to that file (meaning you will no longer see prompts show up in your terminal)
For example:
$ bash > outfile
$ echo "hello"
$ echo "this is an outfile"
$ cd asdsd
bash: cd: asdsd: No such file or directory
$ exit
exit
$ cat outfile
hello
this is an outfile
$
$ bash &> outfile
echo "hi"
echo "this saves everythingggg"
cd asdfasdfasdf
exit
$ cat outfile
hi
this saves everythingggg
bash: line 3: cd: asdfasdfasdf: No such file or directory
$
If you want to see the output and have it written to a file (say for later analysis) then you can use the tee command.
$ echo "hi this is a dude" | tee hello
hi this is a dude
$ ls
hello
$ cat hello
hi this is a dude
tee is a useful command because it allows you to store everything that goes into it as well as displaying it on the screen. Particularly useful for logging the output of scripts.

Copy stderr and stdout to a file as well as the screen in ksh

I'm looking for a solution (similar to the bash code below) to copy both stdout and stderr to a file in addition to the screen within ksh on Solaris.
The following code works great in the bash shell:
#!/usr/bin/bash
# Clear the logfile
>logfile.txt
# Redirect all script output to a logfile as well as their normal locations
exec > >(tee -a logfile.txt)
exec 2> >(tee -a logfile.txt >&2)
date
ls -l /non-existent/path
For some reason this is throwing a syntax error on Solaris. I assume it's because I can't do process substitution, and I've seen some posts suggesting the use of mkfifo, but I've yet to come up with a working solution.
Does anyone know of a way that all output can be redirected to a file in addition to the default locations?
Which version of ksh are you using? The >() is not supported in ksh88, but is supported in ksh93 - the bash code should work unchanged (aside from the #! line) on ksh93.
If you are stuck with ksh88 (poor thing!) then you can emulate the bash/ksh93 behaviour using a named pipe:
#!/bin/ksh
# Clear the logfile
>logfile.txt
pipe1="/tmp/mypipe1.$$"
pipe2="/tmp/mypipe2.$$"
trap 'rm "$pipe1" "$pipe2"' EXIT
mkfifo "$pipe1"
mkfifo "$pipe2"
tee -a logfile.txt < "$pipe1" &
tee -a logfile.txt >&2 < "$pipe2" &
# Redirect all script output to a logfile as well as their normal locations
exec >"$pipe1"
exec 2>"$pipe2"
date
ls -l /non-existent/path
The above is a second version to enable stderr to be redirected to a different file.
How about this:
(some commands ...) 2>&1 | tee logfile.txt
Add -a to the tee command line for subsequent invocations to append rather than overwrite.
In ksh, the following works very well for me
LOG=log_file.$(date +%Y%m%d%H%M%S).txt
{
ls
date
... whatever command
} 2>&1 | tee -a $LOG

Can bash -v output be redirected?

starting bash with -v option produces a long output to the console
$ bash -v
source ~/Dropbox/bin/tim_functions.sh
\#!/bin/bash
...several hundred more lines
I would like to capture the output to a file to make it easier to browse through, but I have tried bash -v 2>&1 > out_bash.txt and bash -v | tee out_bash.txt and cannot capture the information on the terminal screen within a file. It is as if the verbose output is neither stderr or stdout. How can this be?
Can anyone suggest a way to capture the output of bash -v ?
bash -v 2>&1 > out_bash.txt
is not what you want, it should be
bash -v >out_bash.txt 2>&1
I poked around and found this http://www.commandlinefu.com/commands/view/3310/run-a-bash-script-in-debug-mode-show-output-and-save-it-on-a-file
On the website they use
bash -x test.sh 2>&1 | tee out.test, but I tested it with
bash -v test.sh 2>&1 | tee out.test and it worked fine.
you can also use the exec command in the script to redirect all output:
#!/bin/bash
exec >> out.txt 2>> out.txt
set -x
set -v
echo "testing debug of shell scripts"
ls
After reading other helpful answers, I believe this issue has to do with how bash is sending the verbose information to tty--which is somehow different than stderr or stdout. It can be caught with the following work around:
$ screen -L
$ bash -v
$ exit #from the bash session
$ exit #from the screen session
This results in a screenlog.0 file being generated containing the output.
The bash -v output of interest was on a mac running 10.7.3 (Lion) with
$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.)
Another 10.6.8 mac I tried had a less (interesting/verbose) output, despite a similar .bashrc file.
You can use,
bash -v 2>&1 | tee file.txt
or
bash -v 2>&1 | grep search_string
Have you tried wrapping your child bash in a subshell?
( bash -v ) 2>&1 > out_bash.txt

How to silence output in a Bash script?

I have a program that outputs to stdout and would like to silence that output in a Bash script while piping to a file.
For example, running the program will output:
% myprogram
% WELCOME TO MY PROGRAM
% Done.
I want the following script to not output anything to the terminal:
#!/bin/bash
myprogram > sample.s
If it outputs to stderr as well you'll want to silence that. You can do that by redirecting file descriptor 2:
# Send stdout to out.log, stderr to err.log
myprogram > out.log 2> err.log
# Send both stdout and stderr to out.log
myprogram &> out.log # New bash syntax
myprogram > out.log 2>&1 # Older sh syntax
# Log output, hide errors.
myprogram > out.log 2> /dev/null
Redirect stderr to stdout
This will redirect the stderr (which is descriptor 2) to the file descriptor 1 which is the the stdout.
2>&1
Redirect stdout to File
Now when perform this you are redirecting the stdout to the file sample.s
myprogram > sample.s
Redirect stderr and stdout to File
Combining the two commands will result in redirecting both stderr and stdout to sample.s
myprogram > sample.s 2>&1
Redirect stderr and stdout to /dev/null
Redirect to /dev/null if you want to completely silent your application.
myprogram >/dev/null 2>&1
All output:
scriptname &>/dev/null
Portable:
scriptname >/dev/null 2>&1
Portable:
scriptname >/dev/null 2>/dev/null
For newer bash (no portable):
scriptname &>-
If you are still struggling to find an answer, specially if you produced a file for the output, and you prefer a clear alternative:
echo "hi" | grep "use this hack to hide the oputut :) "
If you want STDOUT and STDERR both [everything], then the simplest way is:
#!/bin/bash
myprogram >& sample.s
then run it like ./script, and you will get no output to your terminal. :)
the ">&" means STDERR and STDOUT. the & also works the same way with a pipe: ./script |& sed
that will send everything to sed
Try with:
myprogram &>/dev/null
to get no output
Useful variations:
Get only the STDERR in a file, while hiding any STDOUT even if the
program to hide isn't existing at all. (does not ever hang):
stty -echo && ./programMightNotExist 2> errors.log && stty echo
Detach completely and silence everything, even killing the parent
script won't abort ./prog (Does behave just like nohup):
./prog </dev/null >/dev/null 2>&1 &
nohup can be used as well to fully detach, as follow:
nohup ./prog &
A log file nohup.out will be created aside of the script, use tail -f nohup.out to read it.
Note: This answer is related to the question "How to turn off echo while executing a shell script Linux" which was in turn marked as duplicated to this one.
To actually turn off the echo the command is:
stty -echo
(this is, for instance; when you want to enter a password and you don't want it to be readable. Remember to turn echo on at the end of your script, otherwise the person that runs your script won't see what he/she types in from then on. To turn echo on run:
stty echo
For output only on error:
so [command]

Resources