bash: escape individual lines from `-x` echoing

5,958

Solution 1

xtrace output goes to stderr, so you could redirect stderr to /dev/null:

i_know_what_this_does() {
  echo do stuff
} 2> /dev/null

If you still want to see the errors from the commands run inside the functions, you could do

i_know_what_this_does() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

Note the use of (...) instead of {...} to provide a local scope for that function via a subshell. bash, since version 4.4 now supports local - like in the Almquist shell to make options local to the function (similar to set -o localoptions in zsh), so you could avoid the subshell by doing:

i_know_what_this_does() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

An alternative for bash 4.0 to 4.3 would be to use the $BASH_XTRACEFD variable and have a dedicated file descriptor open on /dev/null for that:

exec 9> /dev/null
set -x
i_know_what_this_does() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Since bash lacks the ability to mark a fd with the close-on-exec flag, that has the side effect of leaking that fd to other commands though.

See also this locvar.sh which contains a few functions to implement local scope for variables and functions in POSIX scripts and also provides with trace_fn and untrace_fn functions to make them xtraced or not.

Solution 2

The reason that set +x is printed is that set -x means "print the command you are about to run, with expansions, before running it. So the shell doesn't know that you want it to not print things until after it has printed the line telling it not to print things. To the best of my knowledge, there's no way of stopping that from happening.

Share:
5,958

Related videos on Youtube

clacke
Author by

clacke

Been working with LotusScript in Notes/Domino for over a decade, worked with WebSphere and related Java technologies for two years. After four years of web development and development support in Hong Kong I am now doing Continuous Integration work in Sweden.

Updated on September 18, 2022

Comments

  • clacke
    clacke over 1 year

    In bash, when running with the -x option, is it possible to exempt individual commands from echoing?

    I'm trying to make the output as neat as possible, so I am running certain parts of my script in a subshell with set +x. However, the row set +x itself is still echoed and adds no valuable information to the output.

    I remember back in the bad old .bat days, when running with echo on, individual lines could be exempted by starting them with a @. Is there any equivalent in bash?

    #!/bin/bash -x
    
    function i_know_what_this_does() {
      (
        set +x
        echo do stuff
      )
    }
    
    echo the next-next line still echoes 'set +x', is that avoidable?
    i_know_what_this_does
    echo and we are back and echoing is back on
    

    When running the above, output is:

    + echo the next-next line still echoes 'set +x,' is that 'avoidable?'
    the next-next line still echoes set +x, is that avoidable?
    + i_know_what_this_does
    + set +x
    do stuff
    + echo and we are back and echoing is back on
    and we are back and echoing is back on
    
  • clacke
    clacke over 11 years
    Sweet! I was looking to see if there were any modifiers I could apply to the function itself, but I didn't think about simply redirecting stderr. Thanks!
  • clacke
    clacke over 11 years
    Btw, stchaz.free.fr/which_interpreter from the same page is pretty awesome and disturbing. :-)
  • clacke
    clacke about 11 years
    And now I came back here again for the second method, silencing set +x without silencing useful stderr output. Thanks again!
  • Stéphane Chazelas
    Stéphane Chazelas over 8 years
    Or to avoid perl (and problems with multi-line commands): +() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
  • clacke
    clacke over 8 years
    No, sorry, unix.stackexchange.com/a/60049/17980 is the solution I was looking for. :-) Do the set -x maneuvers buy me anything compared to just printf >&2 '+ %s\n' "$*"?
  • clacke
    clacke over 8 years
    As in: xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }