Exact vs Substring Process Name Matching in witr: How They Differ
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 (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 namestrings.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 (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, exact matching performs two specific checks:
commLower == lowerName– requires the executable name to match exactlymatchesExactToken(cmdLower, lowerName)– checks for whole-token matches within the command line
The --exact flag is registered in 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, 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 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 (lines 11-28), powers the exact matching mode's command-line analysis. This helper function:
- Splits the command line into whitespace-separated tokens
- Further splits each token on both forward slashes (
/) and backslashes (\) to handle path components - Returns
trueonly 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:
# 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.Containsto find the query anywhere within the executable name or command line, making it more permissive but potentially matching unintended processes. - Exact matching (
--exactor-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
matchesExactTokenfunction ininternal/target/resolve.goimplements 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.govsinternal/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 versus 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →