Skip to content
shellhacks.dev
Debugging

Run a script in trace mode without editing it

Trace a script from outside with bash -x script.sh, and add SHELLOPTS=xtrace to trace the scripts it calls as well, which plain bash -x leaves silent.

2 min read
Summarize in AI

A script you cannot or will not edit misbehaves, and you want to see what it runs.

Shell
cat > child.sh <<'EOF'
#!/bin/bash
echo "child: $1"
EOF
cat > parent.sh <<'EOF'
#!/bin/bash
name=world
echo "parent: $name"
bash child.sh "$name"
EOF
bash -x parent.sh
echo ---
env SHELLOPTS=xtrace bash parent.sh
Text
+ name=world
+ echo 'parent: world'
parent: world
+ bash child.sh world
child: world
---
+ name=world
+ echo 'parent: world'
parent: world
+ bash child.sh world
+ echo 'child: world'
child: world

Starting the interpreter with -x has the same effect as set -x on the first line, so nothing in the file changes. The option is not passed on to other scripts that the first one starts, which is why the child is silent in the first run. SHELLOPTS is a variable that Bash exports and reads at startup, so with xtrace in it every Bash process in the tree traces, as the Bash manual explains.

This works for Bash scripts only, since sh scripts ignore SHELLOPTS unless they run under Bash. The variable is read-only inside a running shell, which is why the second command sets it through env and not as a plain prefix. When the script is executed directly with a shebang, bash -x ./script still works but the shebang line is not honoured, so pass the right interpreter. A script that calls itself or a tool with a lot of output can produce a huge trace; send it to a file with 2> trace.log.

Share

More snippets

Debugging

Stop on the first error and show where

Report where a script failed with trap '...' ERR and set -E. LINENO gives the line, BASH_COMMAND the command and $? the status, even inside functions.

1 min read
Debugging

Trace only part of a script

Trace only the lines you are debugging by wrapping them in set -x and set +x. Write { set +x; } 2>/dev/null so the switch-off command is not traced itself.

1 min read
Debugging

Print each line as it is read

Print every script line as the shell reads it, before expansion, with set -v. Pair it with set -x to see the source line and the expanded command.

1 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.