Skip to content

How to have Bash set -x only apply to the very next command without creating child processes and without calling set +x

This is limited to Bash only, and the answer needs to work on all Bash versions without exception.

I do this now:

(set -x; op2)

and it does what I expect: The op1 is not transcribed, the op2 is transcribed, and then op3 is not. And this has the feature that if “code wedging” occurs whereby op2 has a lot of lines of text, I do not have to remember to call set +x later on, because of the scoping with the parentheses. I do not want set +x to also get transcribed, either as it clutters up the output.

So, how do I do the above without having to explicitly call set +x? I’ve tried curly brackets but they don’t “undo” the set -x like the parentheses do.



Except in the case of modern bash 4.x with the off-by-default BASH_XTRACEFD feature in active use, the following will work fine:

logged_cmd() {
  local rc=0
  set -x
  { { rc=$?; set +x; }; } 2>/dev/null
  return "$rc"

logged_cmd op2

Adding support for cases where BASH_XTRACEFD is in use (to cause set -x logs to go somewhere other than stderr) will require using bash 4.1+ features, which has been explicitly disallowed in the question.

User contributions licensed under: CC BY-SA
9 People found this is helpful