22

Bash has a sometimes-useful feature whereby if you turn on the "-x" option (I believe the symbolic name is xtrace), Bash outputs each line of script as it executes it.

I know of two ways to enable this behavior:

  • In the script itself, say set -x
  • On the command line, pass the -x option to Bash.

Is there any way of turning this option on via environment variables?

(In particular, I'm not invoking Bash myself, so I can't pass any options to it, and the script of interest is inside a compressed archive which I don't really feel like rebuilding. If I could set an environment variable, it would presumably be inherited by all child processes...)

  • The manpage says something about BASHOPTS, but when I try it Bash says that's read-only. (Thanks for not mentioning that in the manpage.)

  • Similarly, SHELLOPTS also seems to be read-only.

  • You can select which FD is used with BASH_XTRACEFD. But I still need to turn tracing on in the first place.

11
  • Can you simply set set -x in the terminal and run the script? Commented Aug 19, 2019 at 11:49
  • Something like: set -x; ./script.sh ; set +x Commented Aug 19, 2019 at 11:52
  • 5
    @ArkadiuszDrabczyk The trace setting is not inherited by child processes. If it (and other shell settings) was, it would make writing scripts really tricky, as you would have to either reset options in every script, or write alternative code paths for each eventuality.
    – Kusalananda
    Commented Aug 19, 2019 at 11:56
  • @Kusalananda: The example I posted works for me and if I understand correctly ./script.sh is a child process, right? Commented Aug 19, 2019 at 12:00
  • 2
    @ArkadiuszDrabczyk In bash 5.0.7, it would trace the call to the shell script, but tracing would not be turned on inside the script itself, i.e. the shell option would not be inherited by the script.
    – Kusalananda
    Commented Aug 19, 2019 at 12:01

1 Answer 1

23

Use env to ignore the readonly flags.

env SHELLOPTS=xtrace ./yourscript

Alternately, if you have set -x in your parent shell, you can export SHELLOPTS to cause it to be copied into the environment, and thus to the child (thanks to Joe Casadonte for this):

set -x           # set xtrace flag
export SHELLOPTS # copy all options, including xtrace flag, to environment
./yourscript
6
  • In my case I could not invoke the script this way, I had to add it to a script being spawned via Java. To do that I added the following to the script: env SHELLOPTS=xtrace; export SHELLOPTS; set -x Commented Feb 9 at 20:06
  • @JoeCasadonte, that doesn't make sense: env SHELLOPTS=xtrace; ... doesn't set SHELLOPTS for any subsequent command in POSIX-compliant shells. (env is an external executable, /usr/bin/env, not a built-in shell feature; as such, it's not capable of modifying the shell's state; whereas env var=val cmd ... tells env to first set var=val in its own environment and then use execve() to replace itself with cmd). Commented Feb 10 at 1:40
  • I had a running Java process (that I could not stop/restart) invoking a shell script, and I needed to turn on xtrace for the shell script and its child scripts, so I did not have the luxury of running env var=val cmd.... As for env not being capable of modifying the shell's state, I think the difference is that, for me, it was modifying the shell script's state. Here's an example with two scripts: /tmp/sleeper (date; sleep 1;) and /tmp/agent (/tmp/sleeper; env SHELLOPTS=xtrace; export SHELLOPTS; set -x; /tmp/sleeper;) -- run /tmp/agent. Commented Feb 24 at 2:47
  • 1
    @JoeCasadonte, in your example above, the env command isn't doing any of the work; set -x changes SHELLOPTS in addition to changing the shell's local state, and export SHELLOPTS tells the shell to copy SHELLOPTS to the environment. Those are the only two moving parts that do anything important. Commented Feb 24 at 14:48
  • @JoeCasadonte, ...that said, I did learn something here -- thank you! Commented Feb 24 at 14:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .