I am writing a SH Shell script in Linux RedHat. Can I use "set -x | tee > output.file"?

75 views Asked by At

At the beginning of my script I have the "set -x" line. This, of course, sends all output to the screen. This is exactly what I like so that I can see what the script is doing and fix issues along the way. Once the script works correctly I comment out the "set -x" line.

I would like to tee the output of set -x so that I have a file to look at instead of using the display only. Is there a way to do this?

I've tried "set -x | tee ScriptNameHere.DEBUG" and it gives me a file named ScriptNameHere.DEBUG with ZERO bytes in it... an empty file.

set -x | tee scriptname.debug set -x | tee -a scriptname.debug

All give me a Zero byte file named scriptname.debug.

2

There are 2 answers

3
Charles Duffy On

You can't do this with sh, but you can do it with bash (as long as you aren't on the ancient version shipped by Apple).

#!/usr/bin/env bash
case $BASH_VERSION in
  ''|[1-3].*|4.[012].*) echo "ERROR: bash 4.3 or newer required" >&2; exit 1;;
esac

exec {BASH_XTRACEFD}> >(tee -a ScriptNameHere.DEBUG >&2)
set -x
# ... other content of your script below

Explaining the above:

  • When exec is passed only redirections, and not a command, it performs those redirections in the current shell.
  • In bash 4.x and later, BASH_XTRACEFD gives the number of the file descriptor where xtrace (set -x) will write logs.
  • Starting somewhere later in the 4.x series (4.1? 4.3?), a redirection of {varname}>file dynamically assigns a file descriptor number to the variable "$varname" of a handle writing to file file.
  • >(...) is a process substitution, replaced with a filename (typically on Linux something like /dev/fd/## or /proc/self/fd/##) that, when written to, will deliver content to the program invoked by the command ...; one for read is instead <(...).

Thus, the net effect is to start a copy of tee in the background and attach it to a file descriptor whose number is written to $BASH_XTRACEFD, such that when set -x is later run, the logs will be written to that copy of tee and thereafter to the specified file.

3
Mark Reed On

set -x | whatever or >wherever just sends the output of the set -x itself - which doesn't output anything! It turns on tracing output, which comes from the shell, not any of the commands the shell runs.

You can capture it, though; just by redirecting stderr, e.g. with

exec 2>>trace.out
set -x

or, to have it go to both the screen and the file

exec 2> >(tee -a trace.out)
set -x