Suppress the bash execution trace (set -x) from the outside of the script

With bash 4.1 and above, you can do

BASH_XTRACEFD=7 ./script.bash 7> /dev/null

(also works when bash is invoked as sh).

Basically, we're telling bash to output the xtrace output on file descriptor 7 instead of the default of 2, and redirect that file descriptor to /dev/null. The fd number is arbitrary. Use a fd above 2 that is not otherwise used in your script. If the shell you're entering this command in is bash or yash, you can even use a number above 9 (though you may run into problems if the file descriptor is used internally by the shell).

If the shell you're calling that bash script from is zsh, you can also do:

(export BASH_XTRACEFD; ./script.bash {BASH_XTRACEFD}> /dev/null)

for the variable to be automatically assigned the first free fd above 9.

For older versions of bash, another option, if the xtrace is turned on with set -x (as opposed to #! /bin/bash -x or set -o xtrace) would be to redefine set as an exported function that does nothing when passed -x (though that would break the script if it (or any other bash script it invokes) used set to set the positional parameters).

Like:

set()
  case $1 in
    (-x) return 0;;
    (-[!-]|"") builtin set "$@";;
    (*) echo >&2 That was a bad idea, try something else; builtin set "$@";;
  esac

export -f set
./script.bash

Another option is to add a DEBUG trap in a $BASH_ENV file that does set +x before every command.

echo 'trap "{ set +x; } 2>/dev/null" DEBUG' > ~/.no-xtrace
BASH_ENV=~/.no-xtrace ./script.bash

That won't work when set -x is done in a sub-shell though.

As @ilkkachu said, provided you have write permission to any folder on the filesystem, you should at least be able to make a copy of the script and edit it.

If there's nowhere you can write a copy of the script, or if it's not convenient to make and edit a new copy every time there's an update to the original script, you may still be able to do:

 bash <(sed 's/set -x/set +x/g' ./script.bash)

That (and the copy approach) may not work properly if the script does anything fancy with $0 or special variables like $BASH_SOURCE (such as looking for files that are relative to the location of the script itself), so you may need to do some more editing like replace $0 with the path of the script...


Since they're scripts, you could make copies of them, and edit those.

Other than that, filtering the output would seem simple, you could explicitly set PS4 to something more unusual than a single plus, to make the filtering easier:

PS4="%%%%" bash script.sh 2>&1 | grep -ve '^%%%%'

(of course that will collapse stdout and stdin, but piping just stderr in Bash gets a bit hairy, so I'll ignore that)

Tags:

Shell

Bash

Set