# How to Use Bash Echo to Echo Shell Commands as They Execute

> Learn how to use bash echo to see shell commands execute. Enable execution tracing with set x to print commands before Bash runs them. Enhance your scripting.

- Repository: [Linus Torvalds/linux](https://github.com/torvalds/linux)
- Tags: how-to-guide
- Published: 2026-02-12

---

**Use `set -x` to enable execution tracing, which prints each command to standard error with a `+` prefix before Bash executes it.**

When debugging complex shell scripts, seeing exactly which commands run and in what order is invaluable. While many developers search for ways to use **bash echo to echo shell commands**, the shell actually provides a built-in execution tracing mechanism that outputs commands automatically as they execute. This feature eliminates the need to manually add `echo` statements throughout your code.

## Understanding Bash Execution Tracing

Bash execution tracing is a built-in debugging feature, not an external command. When active, the shell prints each command to **standard error (stderr)** after performing parameter expansion, command substitution, and arithmetic expansion, but before executing the command.

The trace output uses a **prefix string** defined by the `PS4` variable, which defaults to `+ `. This makes the output appear similar to manually inserted `echo` statements, hence the common search for "bash echo" solutions.

## Enabling Command Echoing with `set -x`

The most common way to enable execution tracing is with the `set` built-in command.

### Enable Tracing in a Script

Place `set -x` at the beginning of your script to trace all subsequent commands:

```bash
#!/usr/bin/env bash

set -x

echo "Starting backup process"
tar -czf backup.tar.gz /home/user/documents
echo "Backup complete"

```

### Enable Tracing for Specific Blocks

Use `set +x` to disable tracing for sections that produce too much noise:

```bash
#!/usr/bin/env bash

set -x

echo "This command is traced"

set +x
echo "This command is not traced"
echo "Neither is this one"
set -x

echo "Tracing resumes here"

```

### Invoke Bash with Tracing Enabled

You can also start a script with tracing already enabled without modifying the script:

```bash
bash -x script.sh

```

## Customizing Trace Output

Bash provides two key variables for controlling how execution traces appear: `PS4` and `BASH_XTRACEFD`.

### Customizing the Prefix with `PS4`

The `PS4` variable defines the string printed before each trace line. You can customize it to include timestamps, line numbers, or source file names.

```bash
#!/usr/bin/env bash

# Include source file, line number, and function name

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

echo "This trace shows exactly where the command is located"

```

Common `PS4` expansions include:

- `${LINENO}` — Current line number in the script
- `${BASH_SOURCE}` — Name of the current source file
- `${FUNCNAME[0]}` — Current function name
- `\t` — Tab character for alignment

### Redirecting Trace Output with `BASH_XTRACEFD`

By default, traces go to stderr. Use `BASH_XTRACEFD` to redirect traces to a specific file descriptor, allowing you to log traces separately from error output.

```bash
#!/usr/bin/env bash

# Open file descriptor 5 for writing to a log file

exec 5>command_trace.log
export BASH_XTRACEFD=5

set -x

echo "This command appears in the log file, not on screen"
ls -la

```

## Practical Examples

### Debugging a Deployment Script

```bash
#!/usr/bin/env bash

set -e  # Exit on error

set -x  # Enable tracing

echo "Deploying application..."
rsync -avz ./build/ user@server:/var/www/app/
ssh user@server "sudo systemctl restart nginx"

set +x
echo "Deployment complete! Check the server logs for details."

```

### Conditional Tracing Based on Debug Mode

```bash
#!/usr/bin/env bash

DEBUG=${DEBUG:-0}

if [[ "$DEBUG" -eq 1 ]]; then
    set -x
    export PS4='+ [DEBUG] ${BASH_SOURCE}:${LINENO}: '
fi

echo "Running in ${DEBUG:+debug }mode"

```

## Summary

- **Use `set -x`** to enable execution tracing, which prints each command to stderr before execution with a `+` prefix.
- **Use `set +x`** to disable tracing for specific code blocks that generate excessive output.
- **Customize `PS4`** to include contextual information like line numbers, source files, and timestamps in trace output.
- **Set `BASH_XTRACEFD`** to redirect trace logs to a file descriptor other than stderr for separate logging.
- **Invoke with `bash -x script.sh`** to enable tracing without modifying the script file.

## Frequently Asked Questions

### How do I echo shell commands in Bash without using the echo command?

Use the built-in execution tracing feature by running `set -x` in your script or invoking Bash with the `-x` flag. This prints each command to standard error before execution, effectively echoing the command without manually adding echo statements throughout your code.

### What is the difference between `set -x` and `set -v` in Bash?

`set -x` prints commands after parameter expansion, command substitution, and arithmetic expansion, showing the actual values being executed. `set -v` prints input lines as they are read, before any processing occurs. Use `-x` for debugging what actually runs, and `-v` to see the raw script input including comments and unexpanded variables.

### How can I redirect Bash trace output to a file instead of stderr?

Set the `BASH_XTRACEFD` variable to a file descriptor number, then open that descriptor for writing to your log file. For example: `exec 5>trace.log; export BASH_XTRACEFD=5; set -x`. This sends all trace output to `trace.log` while keeping stderr clean for actual error messages.

### Can I customize the prefix shown before each traced command?

Yes, modify the `PS4` environment variable to change the trace prefix from the default `+ ` to any string you prefer. You can include dynamic information using parameter expansion such as `${LINENO}` for line numbers, `${BASH_SOURCE}` for filenames, or `${FUNCNAME[0]}` for function names to create more informative debug output.