# Exact vs Substring Process Name Matching in witr: How They Differ

> Understand exact vs substring process name matching in witr. Learn how witr finds processes using different matching modes to improve your workflow.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: deep-dive
- Published: 2026-08-10

---

**witr supports two process name matching modes: substring matching (default) that uses `strings.Contains` to find the query anywhere in the executable name or command line, and exact matching (enabled with `--exact` or `-x`) that requires the executable name to match completely or the query to appear as a whole token in the command line.**

The pranshuparmar/witr process management tool provides flexible process identification through either exact or substring matching for process names. Understanding the difference between these two modes is essential for accurately targeting processes without accidentally matching unintended executables. This article examines the implementation details found in the witr source code to explain how each matching strategy works across Linux, macOS, FreeBSD, and Windows platforms.

## How Process Name Matching Works in witr

witr locates processes by comparing the supplied name against the process's *comm* field (the executable name) and its full command-line arguments. The matching behavior changes significantly depending on whether you use the default substring mode or enable exact matching.

### Substring Matching (Default Behavior)

By default, witr uses **substring matching** to locate processes. In this mode, the tool checks if the supplied name appears anywhere within the process information using Go's `strings.Contains` function.

On Linux and Unix-like systems, as implemented in [`internal/target/name_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_linux.go) (lines 60-64 and 76-80), the code performs case-insensitive substring checks against both the executable name and the command line:

- `strings.Contains(commLower, lowerName)` – checks if the query appears within the executable name
- `strings.Contains(cmdLower, lowerName)` – checks if the query appears anywhere in the full command-line string

Windows follows a similar pattern in [`internal/target/name_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_windows.go) (lines 45-49 and 74-78), checking the executable basename and command line for any occurrence of the query string.

### Exact Matching with the --exact Flag

When you pass the `--exact` or `-x` flag, witr switches to **exact matching** mode. This stricter approach requires the process name to match completely or appear as a discrete token within the command line.

According to the source code in [`internal/target/name_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_linux.go), exact matching performs two specific checks:

1. `commLower == lowerName` – requires the executable name to match exactly
2. `matchesExactToken(cmdLower, lowerName)` – checks for whole-token matches within the command line

The `--exact` flag is registered in [`internal/app/app.go`](https://github.com/pranshuparmar/witr/blob/main/internal/app/app.go) and propagates through the target resolution logic to toggle between these two distinct matching strategies.

## Platform-Specific Implementation Details

### Linux and Unix-like Systems

In [`internal/target/name_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_linux.go), the decision between substring and exact matching occurs around lines 60-80. When `exact` is false, the code uses `strings.Contains` for both the *comm* value read from `/proc/[pid]/comm` and the *cmdline* content from `/proc/[pid]/cmdline`.

When exact mode is enabled, the logic changes to strict equality for the executable name (`commLower == lowerName`) and invokes `matchesExactToken` for command-line parsing. This prevents partial matches—searching for `chrome` will not match `chrome_helper` or `chromium` unless using substring mode.

### Windows Implementation

The Windows implementation in [`internal/target/name_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_windows.go) follows analogous logic at lines 45-49 and 74-78. Substring matching uses `strings.Contains` against the executable basename and full command line.

For exact matching on Windows, the code requires `exeLower == lowerName` for the executable basename and applies `matchesExactToken` to the command-line string. This ensures consistent behavior across platforms while respecting Windows-specific process naming conventions.

## The matchesExactToken Function

The `matchesExactToken` function, defined in [`internal/target/resolve.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/resolve.go) (lines 11-28), powers the exact matching mode's command-line analysis. This helper function:

1. Splits the command line into whitespace-separated tokens
2. Further splits each token on both forward slashes (`/`) and backslashes (`\`) to handle path components
3. Returns `true` only when a token exactly equals the query string

For example, when searching for `core24` with exact matching enabled, the function matches `/snap/core24/1349` because `core24` constitutes a complete path segment, but would not match `core24snapshot` because the token boundaries differ.

## Practical Usage Examples

The following examples demonstrate the behavioral differences between substring and exact matching:

```bash

# Substring (default) – finds any process whose name contains "chrome"

# This matches chrome, chromium, chrome_helper, google-chrome, etc.

witr chrome

# Exact – only matches a process whose executable name is exactly "chrome"

# or has "chrome" as a complete command-line token

witr chrome --exact

# Exact token match – matches a complete path segment

# Suppose a process runs: /usr/bin/python /opt/app/core24/script.py

# The exact flag will match "core24" because it is a complete token/path segment

witr core24 --exact

```

## Summary

- **Substring matching** (default) uses `strings.Contains` to find the query anywhere within the executable name or command line, making it more permissive but potentially matching unintended processes.
- **Exact matching** (`--exact` or `-x`) requires the executable name to match completely or the query to appear as a whole token in the command line, preventing partial string matches.
- The `matchesExactToken` function in [`internal/target/resolve.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/resolve.go) implements token-level matching by splitting on whitespace and path separators to identify valid exact matches.
- Implementation details differ slightly between platforms ([`internal/target/name_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_linux.go) vs [`internal/target/name_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_windows.go)), but the core matching logic remains consistent across Linux, macOS, FreeBSD, and Windows.

## Frequently Asked Questions

### When should I use exact matching instead of substring matching?

Use **exact matching** when you need to target a specific process and want to avoid accidentally matching processes with similar names. For example, if you want to kill a process named `app` but not `application` or `myapp`, use `witr app --exact`. Substring matching works better for quick, broad searches where you only know part of the process name.

### How does witr handle path components when using exact matching?

witr treats path components as separate tokens through the `matchesExactToken` function. When analyzing a path like `/snap/core24/1349`, the function splits on forward and backslashes and recognizes `core24` as a valid exact match. This allows you to match processes by specific directory names or package identifiers that appear in their execution paths without matching partial string occurrences.

### Does exact matching behave differently on Windows compared to Linux?

The core logic remains consistent across platforms, but there are implementation differences in [`internal/target/name_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_windows.go) versus [`internal/target/name_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/target/name_linux.go). Both platforms use `strings.Contains` for substring matching and `matchesExactToken` for exact command-line matching. However, Windows specifically checks the executable basename rather than the full path for the primary executable name comparison, while Unix systems check the *comm* field from `/proc`.

### What is the performance difference between substring and exact matching?

Exact matching potentially offers slightly better performance in high-match scenarios because it can exit early on exact string equality checks (`commLower == lowerName`) before processing command-line tokens. However, both modes require reading process information from the operating system, and the difference is generally negligible for typical usage. The primary consideration should be accuracy rather than performance when choosing between these modes.