Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Shell Script Dictionary
  3. Debugging

Debugging

Since: set -x(トレース) POSIX(sh互換)
PS4 / trap DEBUG / BASH_SOURCE / LINENO Bash(bash拡張)

Shell scripts include built-in debugging features for tracing and inspecting script behavior in detail. set -x enables trace mode, which prints each command to standard error just before it executes, showing the actual values after variable expansion. trap '...' DEBUG lets you insert custom processing before or after every command. You can also customize the PS4 environment variable to add line numbers or timestamps to trace output for even more detail. For full step-through debugging, the interactive debugger bashdb is available.

Syntax

# -----------------------------------------------
#  set -x / set +x  Enable/disable trace mode
# -----------------------------------------------
set -x          # Start tracing subsequent commands
コマンド群
set +x          # Stop tracing

# To trace the entire script, write this right after the shebang
#!/bin/bash
set -x

# -----------------------------------------------
#  PS4  Customize the trace line prefix
# -----------------------------------------------
# Default is "+" (one "+" per nesting level)
# A common setting that adds line number and script name
export PS4='+(${BASH_SOURCE}:${LINENO}): '

# Add a timestamp to measure performance as well
export PS4='[$(date +%T.%3N)] ${BASH_SOURCE}:${LINENO}: '

# -----------------------------------------------
#  trap '...' DEBUG  Intercept before every command
# -----------------------------------------------
trap 'echo "LINE ${LINENO}: ${BASH_COMMAND}"' DEBUG

# -----------------------------------------------
#  bashdb  How to launch the interactive debugger
# -----------------------------------------------
bashdb スクリプト名.sh          # Launch with bashdb
bashdb -- スクリプト名.sh 引数  # Launch with arguments

Debugging Techniques

Technique / SyntaxDescription
set -xEnables trace mode. Prints each command to standard error after variable expansion, just before execution.
set +xDisables trace mode. Wrap only the section you want to inspect to keep output focused.
set -vEnables verbose mode. Prints each line of the script as it is read, before expansion.
PS4Environment variable that sets the prefix string for trace output. Use ${LINENO} and ${BASH_SOURCE} to include line numbers and filenames.
trap '...' DEBUGRuns the specified command just before every command in the script. Can be used as a watchpoint to monitor variable changes.
BASH_COMMANDSpecial variable holding the string of the currently executing command. Referenced inside a trap DEBUG handler.
LINENOSpecial variable holding the current line number. Embed it in error messages or PS4 for location context.
BASH_SOURCEArray of script filenames. Use ${BASH_SOURCE[0]} to get the name of the current file.
FUNCNAMEArray of function names on the call stack. Use ${FUNCNAME[0]} to get the name of the current function.
bashdbAn interactive debugger for bash. Supports breakpoints, step execution, and interactive variable inspection.

Sample Code

db_debug_trace.sh
#!/bin/bash
# -----------------------------------------------
#  Demonstrates trace debugging with set -x and PS4
#  while processing Dragon Ball character data
# -----------------------------------------------

# -----------------------------------------------
#  Customize PS4
#  Add the filename and line number to trace output
# -----------------------------------------------
export PS4='+(${BASH_SOURCE[0]##*/}:${LINENO}): '

# -----------------------------------------------
#  Define character data as arrays
# -----------------------------------------------
characters=("孫悟空" "ベジータ" "ピッコロ" "クリリン" "フリーザ")
powers=(9000 8000 3500 1750 530000)

# -----------------------------------------------
#  Function to find the index of the highest power level
# -----------------------------------------------
find_max_power() {
    local max_index=0
    local max_val=${powers[0]}

    # Compare the power level of each character
    for i in "${!powers[@]}"; do
        if [ "${powers[$i]}" -gt "${max_val}" ]; then
            max_val=${powers[$i]}
            max_index=$i
        fi
    done

    echo "${max_index}"
}

echo "=== 戦闘力ランキング ==="
echo ""

# -----------------------------------------------
#  Trace only this section with set -x
# -----------------------------------------------
set -x

# Get the index of the highest power level
max_idx=$(find_max_power)

# Display the result
echo "最強キャラクター: ${characters[$max_idx]}"
echo "戦闘力: ${powers[$max_idx]}"

set +x
# -----------------------------------------------
#  End of trace mode
# -----------------------------------------------

echo ""
echo "=== 全キャラクター一覧 ==="
for i in "${!characters[@]}"; do
    printf "  %-30s 戦闘力: %6d\n" "${characters[$i]}" "${powers[$i]}"
done
$ chmod +x db_debug_trace.sh
$ ./db_debug_trace.sh
=== 戦闘力ランキング ===

+(db_debug_trace.sh:40): find_max_power
+(db_debug_trace.sh:18): local max_index=0
+(db_debug_trace.sh:19): local max_val=9000
+(db_debug_trace.sh:22): for i in "${!powers[@]}"
+(db_debug_trace.sh:23): '[' 9000 -gt 9000 ']'
+(db_debug_trace.sh:22): for i in "${!powers[@]}"
+(db_debug_trace.sh:23): '[' 8000 -gt 9000 ']'
+(db_debug_trace.sh:22): for i in "${!powers[@]}"
+(db_debug_trace.sh:23): '[' 3500 -gt 9000 ']'
+(db_debug_trace.sh:22): for i in "${!powers[@]}"
+(db_debug_trace.sh:23): '[' 1750 -gt 9000 ']'
+(db_debug_trace.sh:22): for i in "${!powers[@]}"
+(db_debug_trace.sh:23): '[' 530000 -gt 9000 ']'
+(db_debug_trace.sh:24): max_val=530000
+(db_debug_trace.sh:25): max_index=4
+(db_debug_trace.sh:29): echo 4
+(db_debug_trace.sh:40): max_idx=4
+(db_debug_trace.sh:43): echo '最強キャラクター: フリーザ'
最強キャラクター: フリーザ
+(db_debug_trace.sh:44): echo '戦闘力: 530000'
戦闘力: 530000
+(db_debug_trace.sh:46): set +x

=== 全キャラクター一覧 ===
  孫悟空                         戦闘力:   9000
  ベジータ                       戦闘力:   8000
  ピッコロ                       戦闘力:   3500
  クリリン                       戦闘力:   1750
  フリーザ                       戦闘力: 530000
db_debug_trap.sh
#!/bin/bash
# -----------------------------------------------
#  Uses trap '...' DEBUG to watch for variable changes.
#  Tracks score accumulation for Dragon Ball characters
#  command by command.
# -----------------------------------------------

# -----------------------------------------------
#  Specify the variable name to watch.
#  Prints a message whenever this variable changes.
# -----------------------------------------------
WATCH_VAR="total_score"
total_score=0

# -----------------------------------------------
#  DEBUG trap handler
#  Called before every command.
#  BASH_COMMAND holds the command about to be executed.
# -----------------------------------------------
debug_handler() {
    # Only log commands that involve total_score
    case "${BASH_COMMAND}" in
        *total_score*) echo "  [DEBUG L${LINENO}] CMD: ${BASH_COMMAND}" >&2 ;;
    esac
}

trap debug_handler DEBUG

# -----------------------------------------------
#  Accumulate battle scores for Dragon Ball characters
# -----------------------------------------------
declare -A scores
scores["孫悟空"]=3
scores["ベジータ"]=2
scores["ピッコロ"]=4
scores["クリリン"]=1
scores["フリーザ"]=5

echo "=== バトルスコア集計 ==="
echo ""

for name in "孫悟空" "ベジータ" "ピッコロ" "クリリン" "フリーザ"; do
    point=${scores[$name]}
    total_score=$((total_score + point))
    echo "  ${name}: ${point}点 (累計: ${total_score}点)"
done

echo ""
echo "=== 最終合計: ${total_score}点 ==="

# Remove the DEBUG trap
trap - DEBUG
$ chmod +x db_debug_trap.sh
$ ./db_debug_trap.sh
=== バトルスコア集計 ===

  [DEBUG L42] CMD: total_score=$((total_score + point))
  孫悟空: 3点 (累計: 3点)
  [DEBUG L42] CMD: total_score=$((total_score + point))
  ベジータ: 2点 (累計: 5点)
  [DEBUG L42] CMD: total_score=$((total_score + point))
  ピッコロ: 4点 (累計: 9点)
  [DEBUG L42] CMD: total_score=$((total_score + point))
  クリリン: 1点 (累計: 10点)
  [DEBUG L42] CMD: total_score=$((total_score + point))
  フリーザ: 5点 (累計: 15点)

=== 最終合計: 15点 ===

Notes

A step-by-step approach is effective for debugging shell scripts. Start by enabling trace mode with set -x to see commands after variable expansion. If the output becomes too noisy, wrap only the section you care about between set -x and set +x. Setting PS4 to ${BASH_SOURCE[0]##*/}:${LINENO} adds the filename and line number, so you can immediately pinpoint where and what is happening.

trap '...' DEBUG intercepts execution before every command. Combined with the BASH_COMMAND variable, it acts as a watchpoint that selectively logs only the changes you care about. The special variables LINENO, BASH_SOURCE, and FUNCNAME let you embed location information in error messages. Use bashdb for full-featured debugging that requires breakpoints and step execution. For the basics of signals, see also trap (signal handling); for script-wide error control, see set options (-e / -u / -o pipefail).

If you find any errors or copyright issues, please .