how to silently disable xtrace in a shell script?

Next command disables 'xtrace' option:

$ set +o xtrace


Sandbox it in a subshell:

(set -x; do_thing_you_want_traced)

Of course, changes to variables or the environment made in that subshell will be lost.

If you REALLY care about this, you could also use a DEBUG trap (using set -T to cause it to be inherited by functions) to implement your own set -x equivalent.

For instance, if using bash:

trap_fn() {
  [[ $DEBUG && $BASH_COMMAND != "unset DEBUG" ]] && \
    printf "[%s:%s] %s\n" "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND"
  return 0 # do not block execution in extdebug mode
}
trap trap_fn DEBUG

DEBUG=1
# ...do something you want traced...
unset DEBUG

That said, emitting BASH_COMMAND (as a DEBUG trap can do) is not fully equivalent of set -x; for instance, it does not show post-expansion values.


You want to try using a single-line xtrace:

function xtrace() {
  # Print the line as if xtrace was turned on, using perl to filter out
  # the extra colon character and the following "set +x" line.
  (
    set -x
    # Colon is a no-op in bash, so nothing will execute.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

The original command executes in the same shell under an identity transformation. Just prior to running, you get a non-recursive xtrace of the arguments. This allows you to xtrace the commands you care about without spamming stederr with duplicate copies of every "echo" command.

# Example
for value in $long_list; do
  computed_value=$(echo "$value" | sed 's/.../...')
  xtrace some_command -x -y -z $value $computed_value ...
done

Tags:

Shell