Chapter 17Lesson 01~95 minutes

Tracing with set -x, PS4, and Selective Debug Output

Bash tracing can show exactly what the shell executes after expansion, but indiscriminate xtrace is noisy and can expose secrets. Effective debugging narrows the trace and gives every line useful context.

IntermediateTesting & debuggingHands-on lab

Learning objectives

By the end of this lesson

  • Explain what xtrace reveals.
  • Customize PS4 context.
  • Route traces separately.
  • Protect secret-bearing operations.
  • Choose selective debug logging when appropriate.

1. xtrace shows commands after expansion

set -x enables Bash execution tracing. Bash prints each command after parameter, command, and arithmetic expansion, immediately before execution.

What xtrace reveals
flowchart LR
  S["source command"] --> E["shell expansions"]
  E --> X["xtrace line"]
  E --> C["command execution"]
Security boundary

Expanded values can include credentials. Never treat xtrace as safe around secrets.

2. Enable and disable tracing selectively

set -x
build_project
run_tests
set +x

publish_secret_bearing_step

A short trace window is easier to audit and far easier to read than tracing an entire pipeline.

3. PS4 adds useful context

PS4='+ ${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]:-main}: '
set -x

do_work() {
  printf 'working\n'
}

do_work
set +x

File, line, and function names turn trace output into a navigable execution record.

4. Route traces to a dedicated descriptor

exec 19>trace.log
export BASH_XTRACEFD=19
PS4='+ ${BASH_SOURCE}:${LINENO}: '

set -x
run_build
set +x

exec 19>&-

BASH_XTRACEFD can separate trace output from stdout and stderr on supported Bash versions.

5. Disable tracing before credentials are expanded

set -x
prepare_request
set +x

curl \
  --header "Authorization: Bearer $API_TOKEN" \
  --silent \
  "$url"

set -x
verify_response
set +x
Masking is not enough

CI masking may not recognize transformed, encoded, or partial secret values.

6. Use a subshell to contain debug options

(
  PS4='+ debug:${LINENO}: '
  set -x
  reproduce_failure
)

printf 'parent tracing unchanged\n'

Subshell containment is useful when you want debug state to disappear automatically.

7. Custom debug logging is often safer

DEBUG=${DEBUG:-false}

debug() {
  [[ $DEBUG == true ]] || return 0
  printf 'DEBUG phase=%q service=%q\n' "$phase" "$service" >&2
}

A custom logger reveals only the fields you deliberately choose.

8. xtrace and verbose input are different

set -x traces execution after expansion; set -v prints shell input as read. Use the mode that answers the actual debugging question.

9. Rich PS4 expressions have a cost

PS4='+ $(date -u "+%H:%M:%S") ${LINENO}: '
set -x
slow_operation
set +x

Command substitutions in PS4 run for every trace line. Use expensive prefixes only while diagnosing a problem.

10. Hands-on lab: targeted trace file

mkdir -p "$HOME/devops-academy/bash/chapter17/lesson01"
cd "$HOME/devops-academy/bash/chapter17/lesson01"

cat > trace-demo.sh <<'EOF'
#!/usr/bin/env bash
set -u

exec 19>trace.log
export BASH_XTRACEFD=19
PS4='+ ${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]:-main}: '

calculate() {
  local a=$1 b=$2
  printf 'total=%d\n' "$((a + b))"
}

set -x
calculate 3 4
set +x

secret='never-trace-this'
printf 'secret_present=%s\n' "$([[ -n $secret ]] && printf yes)"
exec 19>&-
EOF

chmod u+x trace-demo.sh
bash trace-demo.sh
cat trace.log

Verification checklist

11. Knowledge check

Question 1. What does xtrace print?

Question 2. What does PS4 control?

Question 3. Why use BASH_XTRACEFD?

Question 4. When is custom debug logging preferable?

12. Summary

Use xtrace as a scalpel: narrow its scope, enrich it with PS4, separate it from ordinary output, and turn it off before secret-bearing operations.

13. Further reading

  • GNU Bash Reference Manual — The Set Builtin.
  • GNU Bash Reference Manual — PS4 and BASH_XTRACEFD.
  • ShellCheck documentation.
  • OWASP secret-safe logging guidance.
Next lesson

Static Analysis with ShellCheck

Continue Chapter 17 by turning Bash quality and debugging practices into a repeatable engineering workflow.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.