Bash set +x without it being printed
BashShellBash Problem Overview
Does anyone know if we can say set +x
in bash without it being printed:
set -x
command
set +x
traces
+ command
+ set +x
but it should just print
+ command
Bash is Version 4.1.10(4). This is bugging me for some time now - output is cluttered with useless set +x
lines, making the trace facility not as useful as it could be.
Bash Solutions
Solution 1 - Bash
I had the same problem, and I was able to find a solution that doesn't use a subshell:
set -x
command
{ set +x; } 2>/dev/null
Solution 2 - Bash
You can use a subshell. Upon exiting the subshell, the setting to x
will be lost:
( set -x ; command )
Solution 3 - Bash
How about a solution based on a simplified version of @user108471:
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ set +x; } 2>/dev/null'
trace_on
...stuff...
trace_off
Solution 4 - Bash
I hacked up a solution to this just recently when I became annoyed with it:
shopt -s expand_aliases
_xtrace() {
case $1 in
on) set -x ;;
off) set +x ;;
esac
}
alias xtrace='{ _xtrace $(cat); } 2>/dev/null <<<'
This allows you to enable and disable xtrace as in the following, where I'm logging how the arguments are assigned to variables:
xtrace on
ARG1=$1
ARG2=$2
xtrace off
And you get output that looks like:
$ ./script.sh one two
+ ARG1=one
+ ARG2=two
Solution 5 - Bash
This is a combination of a few ideas that can enclose a block of code and preserves the exit status.
#!/bin/bash
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ PREV_STATUS=$? ; set +x; } 2>/dev/null; (exit $PREV_STATUS)'
trace_on
echo hello
trace_off
echo "status: $?"
trace_on
(exit 56)
trace_off
echo "status: $?"
When executed:
$ ./test.sh
+ echo hello
hello
status: 0
+ exit 56
status: 56
Solution 6 - Bash
Here is another one. Often you only want to trace a particular command in your script. Then why not write a function that does just that?
> call() { set -x; "$@"; { set +x; } 2>/dev/null; }
> call uname -a
+ uname -a
CYGWIN_NT-6.1-WOW W530 3.1.7(0.340/5/3) 2020-08-22 19:03 i686 Cygwin
> call make -j8 *.mak
+ make -j8 some_name.mak
We can improve this further by returning (and tracing) the exit code of the called command:
> call() { local rc; set -x; "$@"; rc=$?; { set +x; } 2>/dev/null; return $rc; }
> call true && echo yes
+ true
+ rc=0
yes
> call false && echo yes
+ false
+ rc=1
Here is a real life example that calls the Rhapsody CLI program to generate source code from a .rcl-file with command-line options:
die() {
local c=${1:--1} m=${2:-'Died'}
echo "$m at ${BASH_SOURCE[1]}:${FUNCNAME[1]} line ${BASH_LINENO[0]} (exit $c)" >&2
exit $c
}
call() { local rc; set -x; "$@"; rc=$?; { set +x; } 2>/dev/null; return $rc; }
call "$opt_rhapsodycl" -f $rclfile || die $? 'Rhapsody license server not reachable'
For example, in case of failure prints something like:
+ path/to/RhapsodyCL.exe -f configuration.rcl
+ rc=127
Rhapsody license server not reachable at ./Build:main line 167 (exit 127)
Or in case of success the script continues. With these two functions (call
and die
) we can write very compact and readable one-liners that also produce nice tracing output.