11

Is it possible to test whether a bash script was executed with -x?

I'm writing a script which also runs some remote scripts, and I'd like to be able to do something like:

USE_X="$( run_with_x && "-x" || "" )"
ssh $host "bash $USE_X some_script.sh"
10

Just look at the $- variable.

USE_X=`case "$-" in *x*) echo "-x" ;; esac`

(Yup, I did manage to do that without invoking grep. Save the pids!)

5
  • what does *x* expand to?
    – bbaja42
    Oct 3 '11 at 6:55
  • 2
    What a waste of pid! case $- in *x*) USE_X="-x";; *) USE_X=;; esac @bbaja42 It doesn't expand to anything: it's a pattern that the string $- is matched against. Oct 3 '11 at 21:08
  • @Gilles Your example also contains unnecessary part: *) USE_X=;; changes nothing, if USE_X was not set previously. Also, the whole case construct is unnecessary (see my version - isn't that simpler?) Oct 4 '11 at 16:12
  • @rozcietrzewiacz This part is unnecessary if USE_X has been initialized earlier on. I don't consider your version simpler: it's a few characters shorter (and even then only if USE_X has been initialized, otherwise it's longer), but at the expense of clarity and portability. Oct 4 '11 at 17:11
  • @Gilles Portability is not the subject of this question, it is about bash. Initializing USE_X is not necessary for the purpose of OP's intended use (to pass $USE_X to further scripts). Using case construct looks less clear and natural than a regular condition evaluation in my view. Oct 4 '11 at 17:53
8

This expression will be true if the script is run with -x, false otherwise: [[ $- =~ x ]] So this expression will be "-x" if the script is run with -x and "" (empty) otherwise: $([[ $- =~ x ]] && echo "-x")

3
  • It's a stretch to say "readable" and "bash" in the same sentence, but since any non-casual bash user MUST get familiar with the bash regex syntax, your (currently lowest-voted) answer wins for readability in my book (and, of course, doesn't require starting any processes or anything astoundingly inefficient).
    – Ron Burk
    Apr 24 '17 at 21:39
  • 1
    This is the best answer! Jun 28 '17 at 15:54
  • This expression removes all non-x characters from $-, so it is empty if there is no x: ${-//[^x]} If you assign this to variable, like: x=${-//[^x]} then the following expression will be empty when there was no x and -x otherwise: ${x:+-x} Combine like: x=${-//[^x]} USE_X=${x:+-x} Or if you don't want to use an extra variable, you can reuse USE_X: USE_X=${-//[^x]} USE_X=${USE_X:+-x} This is much much faster than doing a regular expression comparison! (But less readable just looking at the code, figuring out what it does...)
    – PePa
    May 22 '18 at 8:47
7

Probably the simplest way of parsing $-, similar to dagbrown's method (also pure bash), but without using case and backticks (subshell):

if  [[ ${-/x} != $- ]] ; then USE_X="-x"; fi

or even shorter:

[[ ${-/x} != $- ]] && USE_X="-x"

Note that [[ is not an invocation of test builtin program (as is the case with [), but a bash syntax construct (according to man bash and this dev recommendation). So I claim it to be "purer bash" ;)

1
  • Nice solution. I suggest tagging '|| USE_X="+x"' on the end of the second expression so you may then call 'set "$USE_X"' and it will work to restore the initial setting whether or not xtrace was set. Dec 23 '14 at 15:14
4

After reading man pages and grepping for things, here's the solution:

$ cat show_x.sh
#!/bin/bash
if [ "$(set | grep xtrace)" ]; then
    echo "xtrace is on. :D"
else
    echo "xtrace is off. :("
fi

Result:

$ bash show_x.sh 
xtrace is off. :(

$ bash -x show_x.sh 
++ set
++ grep xtrace
+ '[' SHELLOPTS=braceexpand:hashall:interactive-comments:xtrace ']'
+ echo 'xtrace is on. :D'
xtrace is on. :D
1
  • "set" will show you all the functions and env vars to, and if any of those contain "xtrace" the solution will fail. Jun 28 '17 at 15:40
4

The bash man page documents set -o xtrace as equivalent to set -x, which in turn is equivalent to giving -x as an argument to the shell. (So far, this is compatible with SUSv3 sh, with the caveat that -o option is required "if the system supports the User Portability Utilities option".)

Also, set -o without an option prints the current status of all of the -o options. (SUSv3 specifies this as well, but not usefully; the format is unspecified, so you can only depend on it if you know you're running a shell that uses a format similar to bash's.)

So, the pipeline set -o | grep xtrace | grep -q on should be what you're looking for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.