How do I redirect the output from a bash script to stderr - linux

I've written a bash script. It has a few echo statements. It invokes a few 3rd party tools. I would like to redirect everything that goes to stdout (from my echo statements and all the tools output) to stderr. How do I do that?

You need to redirect the stdout of the command to stderr.
your_command.sh 1>&2
If you want to do this from within the script, you can wrap your whole script into one function and redirect its output to stderr:
main() {
echo hello
echo world
some_script.sh
}
main 1>&2

exec >&2
Put that at the top of your script to redirect all future output to stderr.
$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
Replace the shell with the given command.
Execute COMMAND, replacing this shell with the specified program.
ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
any redirections take effect in the current shell.

The solution that worked for me was to enclose the text of the script within ()'s and redirect stdout to stderr like so:
(
echo 1
echo 2
tool1
) 1>&2

Related

How to redirect STDOUT and STDERR in a file for every command? [duplicate]

This question already has answers here:
How to redirect output of an entire shell script within the script itself?
(6 answers)
Closed 3 years ago.
I'm trying to store both STDOUT and STDERR from the terminal (and if possible STDIN given by user) in a file for every command.
So i started creating a trap function to execute every command in a edited manner like:
shopt -s extdebug
preexec_invoke_exec () {
[ -n "$COMP_LINE" ] && return # do nothing if completing
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
eval `history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"` |& tee ~/recent_output.txt
return 1 # This prevent executing of original command
}
trap 'preexec_invoke_exec' DEBUG
and saving the above file and executing
source file.sh
This did the work what i wanted but stopped some commands from executing like
cd ..
The reason for this was piping creates a sub-shell and then executes every command in it. So the main shell remains unaffected.
Even the script functionality of bash i.e
script ~/recent_output.txt
worked but only gives output after you do exit in in terminal
So, basically i want to store/get the output of previous command executed in the bash terminal. You can help me with any language (golang,python...).
It is possible to capture commands, stderr and stdout of a bash script (say x.sh), using:
bash -x x.sh 2> >(tee err.txt) | tee out.txt
The err.txt will capture the executed commands (prefixed with '+'), and the stderr of each command. The out.txt will capture the output

command to redirect output to console and to a file at the same time works fine in bash. But how do i make it work in korn shell(ksh)

command to redirect output to console and to a file at the same time works fine in bash. But how do i make it work in korn shell(ksh).
All my scripts runs on korn shell so cant change them to bash for this particular command to work.
exec > >(tee -a $LOGFILE) 2>&1
In the code beneath I use the variable logfile, lowercase is better.
You can try something like
touch "${logfile}"
tail -f "${logfile}"&
tailpid=$!
trap 'kill -9 ${tailpid}' EXIT INT TERM
exec 1>"${logfile}" 2>&1
A not too unreasonable technique is to re-exec the shell with output to tee. That is, at the top of the script, do something like:
#!/bin/sh
test -z "$REXEC" && { REXEC=1 exec "$0" "$#" | tee -a $LOGFILE; exit; }

Where does echo output go to, when running a bash script?

The following will output to stdout if the script is run in a terminal:
echo "some message"
If the script is called by another script, where does the output go to? Is there any significant overhead involved?
I'm using GNU bash, version 4.3.33.
Many thanks
The output of
echo "some message"
should go to the stdout except (not exclusive) in cases where
You have a o/p redirection, as given below, which affect the echo statement.
exec 1>/dev/null # 1 is the file descriptor for stdout, this should be before the echo
./script >outfile # The whole output is redirected to a file
You have a do-nothing directive(:) before the echo command
: echo "some message" # Does nothing

How to turn off echo while executing a shell script Linux [duplicate]

This question already has answers here:
How to silence output in a Bash script?
(9 answers)
Closed 6 years ago.
Here is a simple thing i was working on
echo "please enter a command"
read x
$x
checkexitstatus()
{...}
checkexit status is a ifloop created somewhere else just to check exit status
What i want to know is
Is there any way that when i run the $x that it wont be displayed on the screen
I want to know if it is possible without redirecting the output to a file
No, it isn't possible.
$x &> /dev/null
You could use Bash redirection :
command 1> /.../path_to_file => to redirect stdout into path_to_file.
command > /.../path_to_file is a shortcut of the previous command.
command 2> /.../path_to_file => to redirect stderr into path_to_file
To do both at the same time to the same output: command >/.../path_to_file 2>&1.
2>&1 means redirect 2 (stderr) to 1 (stdout which became path_to_file).
You could replace path_to_file by /dev/null if you don't want to retrieve the output of your command.
Otherwise, you could also store the output of a command :
$ var=$(command) # Recent shell like Bash or KSH
$ var=`command` # POSIX compliant
In this example, the output of command will be stored in $var.
If you want to turn off only the echo command and not other commands that send their output to the stdout, as the title suggests, you can possibly (it may break the code) create an alias for echo
alias echo=':'
now echo is an alias for noop. You can unalias it by unalias echo.

How do I know if a bash script is running with nohup?

I have a script to process records in some files, it usually takes 1-2 hours. When it's running, it prints a progress of number of records processed.
Now, what I want to do is: when it's running with nohup, I don't want it to print the progress; it should print progress only when it run manually.
My question is how do I know if a bash script is running with nohup?
Suppose the command is nohup myscript.sh &. In the script, how do I get the nohup from command line? I tried to use $0, but it gives myscript.sh.
Checking for file redirections is not robust, since nohup can be (and often is) used in scripts where stdin, stdout and/or stderr are already explicitly redirected.
Aside from these redirections, the only thing nohup does is ignore the SIGHUP signal (thanks to Blrfl for the link.)
So, really what we're asking for is a way to detect if SIGHUP is being ignored. In linux, the signal ignore mask is exposed in /proc/$PID/status, in the least-significant bit of the SigIgn hex string.
Provided we know the pid of the bash script we want to check, we can use egrep. Here I see if the current shell is ignoring SIGHUP (i.e. is "nohuppy"):
$ egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status && echo nohuppy || echo normal
normal
$ nohup bash -c 'egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status && echo nohuppy || echo normal'; cat nohup.out
nohup: ignoring input and appending output to `nohup.out'
nohuppy
You could check if STDOUT is associated with a terminal:
[ -t 1 ]
You can either check if the parent pid is 1:
if [ $PPID -eq 1 ] ; then
echo "Parent pid=1 (runing via nohup)"
else
echo "Parent pid<>1 (NOT running via nohup)"
fi
or if your script ignores the SIGHUP signal (see https://stackoverflow.com/a/35638712/1011025):
if egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status ; then
echo "Ignores SIGHUP (runing via nohup)"
else
echo "Doesn't ignore SIGHUP (NOT running via nohup)"
fi
One way, but not really portable would be to do a readlink on /proc/$$/fd/1 and test if it ends with nohup.out.
Assuming you are on the pts0 terminal (not really relevant, just to be able to show the result):
#!/bin/bash
if [[ $(readlink /proc/$$/fd/1) =~ nohup.out$ ]]; then
echo "Running under hup" >> /dev/pts/0
fi
But the traditional approach to such problems is to test if the output is a terminal:
[ -t 1 ]
Thank you guys. Check STDOUT is a good idea. I just find another way to do it. That is to test tty.
test tty -s check its return code. If it's 0 , then it's running on a terminal; if it's 1 then it's running with nohup.

Resources