> ## Documentation Index
> Fetch the complete documentation index at: https://wireblast.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Scripting and automation

> Run Wireblast unattended, get parseable output, and get past confirmations deliberately.

Every field in the wizard is a flag, so anything you work out interactively can be pasted into a script.

## The three ways to start

| Command                  | Wizard | Dashboard | Use for                                  |
| ------------------------ | ------ | --------- | ---------------------------------------- |
| `wireblast`              | yes    | yes       | Exploring, first runs                    |
| `wireblast --start ...`  | no     | yes       | You know the settings, you want to watch |
| `wireblast --no-tui ...` | no     | no        | Scripts, CI, `nohup`, no terminal at all |

`--no-tui` validates the flags, runs, and prints plain text to stdout. No terminal required.

```bash theme={null}
sudo wireblast --no-tui -i eno2 --dst-ip 192.0.2.10 \
  --packet-size 512 --pps 100k -d 10s -y
```

## What it prints

A plan, a start line, one line per second, and a summary:

```text theme={null}
destination   192.168.0.2/32 port 9000
next hop      3c:ec:ef:b4:c2:dc (given with --dst-mac)
flows         64
rate          200kpps (aggregate across queues)
duration      12s

attaching XDP to eno2 and waiting for the link...
link came back after 11.8s
started: eno2: 12 queue(s), zero-copy, native XDP, driver ixgbe, rx filter none
running for 12s (Ctrl-C to stop early)

[0:01] tx 149.89 k pkts  199.71 kpps  L1 610.02 Mbit/s  L2 578.07 Mbit/s  avg 362B
[0:02] tx 350.02 k pkts  200 kpps  L1 610.95 Mbit/s  L2 578.95 Mbit/s  avg 362B

ran for 0:12
  tx: 2.4 M packets, 868.24 MB, 199.86 kpps, L1 610.52 Mbit/s, L2 578.54 Mbit/s, avg frame 362B
      udp 2.4 M, tcp 0, other 0
```

<Note>
  There's no `--json` yet. Parsing is text parsing for now, and the `ran for` summary block is the stable thing to key on.
</Note>

Extracting the totals:

```bash theme={null}
sudo wireblast --no-tui -i eno2 --dst-ip 192.0.2.10 --pps 1M -d 30s -y \
  | awk '/^  tx:/ {print $2, $3}'
```

## Exit codes

| Code  | Meaning                                                              |
| ----- | -------------------------------------------------------------------- |
| `0`   | Ran to completion, or was stopped cleanly with Ctrl-C                |
| `1`   | Something went wrong. The reason is on stderr, prefixed `wireblast:` |
| `130` | A second interrupt while shutting down, the emergency exit           |

Errors go to **stderr**, statistics to **stdout**, so you can separate them:

```bash theme={null}
sudo wireblast --no-tui ... 2>/var/log/wireblast.err | tee /var/log/wireblast.out
```

## Confirmations

Some runs stop and ask. There are two levels, and they behave differently on purpose.

**Ordinary confirmations** cover things like your SSH session being on this interface, or unlimited rate on the default-route interface. `--yes` (or `-y`) answers these:

```bash theme={null}
sudo wireblast --no-tui -i eno2 --pps unlimited -d 30s --yes
```

**The match-all guard** covers `--rx-mode all`. `--yes` does not answer this one. You need `--allow-match-all` as well:

```bash theme={null}
sudo wireblast --no-tui -i eth1 --mode receive \
  --rx-mode all --allow-match-all --yes -d 60s
```

<Warning>
  This is deliberate. `--yes` means "I've read the warnings". `--allow-match-all` means "I specifically accept that every packet on this interface stops reaching the kernel, including SSH". They're different statements and Wireblast makes you make both.
</Warning>

Without a terminal and without the flags, it refuses rather than hanging:

```text theme={null}
this run needs an explicit confirmation but there is no terminal to ask on.
Re-run it interactively, or pass --yes together with --allow-match-all if you
have read the warnings above
```

## Saved settings don't apply

`--no-tui` **neither reads nor writes** the saved settings in `~/.wireblast/`. A scripted run depends only on its flags, so it behaves identically on a fresh machine and on one you've been experimenting on all afternoon.

If you're scripting the TUI form (`--start`) and want to ignore whatever was saved:

```bash theme={null}
sudo wireblast --forget
```

That clears the files and starts from defaults.

## Running unattended

```bash theme={null}
sudo nohup wireblast --no-tui -i eno2 --dst-ip 192.0.2.10 \
  --pps 1M -d 3600s -y > /var/log/wireblast.log 2>&1 &
```

Wireblast handles `SIGINT` and `SIGTERM` cleanly: it drains the transmit rings, collects final counts, detaches the XDP program, and exits 0. So `kill` on that PID gives you a proper summary rather than a truncated log.

A second signal exits immediately with 130, so a wedged run can still be killed without reaching for another shell.

<Note>
  `--no-tui` attaches and detaches per run, so each invocation pays the link bounce. Looping many short runs in a shell script costs about 8 seconds each on a physical NIC. If you're iterating, one longer run, or the TUI's `r` key, is much faster.
</Note>

## A two-box script

```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail

RECEIVER=192.0.2.20
IFACE=eno2
DUR=30

ssh root@$RECEIVER "nohup wireblast --no-tui -i $IFACE --mode receive \
  --rx-mode udp-port --rx-port 9000 -d $((DUR + 20))s -y \
  > /tmp/rx.log 2>&1 &"

sleep 2

sudo wireblast --no-tui -i $IFACE --dst-ip 192.0.2.20 --dst-port 9000 \
  --packet-size 512 --pps 1M -d ${DUR}s -y

ssh root@$RECEIVER "until grep -q '^ran for' /tmp/rx.log; do sleep 2; done; \
  grep -A3 '^ran for' /tmp/rx.log"
```

Give the receiver a longer duration than the sender so it's listening for the whole run, and start it first. Packets sent before it attaches are simply gone.

The [examples directory](https://github.com/atoonk/wireblast/tree/main/examples) has ready-made scripts for most of this, all driven by environment variables.
