A comprehensive guide for humans to learn and use nin - the set operation tool for lines and keys.
nin (Not-IN) is a command-line tool that helps you:
- Find lines/keys in one file that are not in another file (difference set)
- Find lines/keys that are in both files (intersection set)
- Get unique lines/keys and remove duplicates
- Analyze distribution and percentages of keys
- Compare files or pipe input with flexible regex patterns
Runs on Windows, Linux, macOS, and FreeBSD (multiple architectures including x86_64, Arm64). For the complete platform/architecture/version matrix, see Download Links.
For encoding matrix, BOM detection behavior, and cross-platform Unicode notes, see msr and nin Shared Reference — Encoding Support.
nin is distributed together with msr. The easiest way is to install the vscode-msr extension which auto-downloads both tools automatically.
For manual download on any platform (Windows, Linux, macOS, FreeBSD, Cygwin), see: → Download Links by Platform
Verify download integrity with md5:
md5sum nin* | msr -t "\s+\**" -o " " -PAC | nin md5.txt -m# Find lines in file1.txt that are NOT in file2.txt
nin file1.txt file2.txt
# Find keys (first word) in file1 that are NOT in file2
nin file1.txt file2.txt "^(\w+)"
# Using pipe input (single-stream analysis)
cat file1.txt | nin nul# Find common lines in both files
nin file1.txt file2.txt -m
# Find common keys with case-insensitive matching
nin file1.txt file2.txt "^(\w+)" -im# Remove duplicate lines (keep original order)
nin myfile.txt nul -u
# Remove duplicates, ignore case
nin myfile.txt nul -ui
# From pipe
cat myfile.txt | nin nul -uiWhen you only have one file, use nul (Windows) or /dev/null (Linux) as the second file:
# These are equivalent - get unique lines
nin myfile.txt nul -u
nin myfile.txt /dev/null -u # Linux/MacNote: For Windows path separator compatibility in file arguments, see msr and nin Shared Reference — Path Separator Compatibility on Windows.
nin uses capture group[1] as the key for comparison:
# Extract first word as key
nin file.txt nul "^(\w+)"
# Extract email addresses
nin file.txt nul "(\w+@\w+\.\w+)"
# Extract key from key=value pairs
nin config.txt nul "^(\w+)\s*="You can use different regex patterns for each file:
# File1: "name = John", File2: "John,Smith,30"
nin file1.txt file2.txt "name = (\w+)" "^(\w+),"# New items in today's list vs yesterday's
nin today.txt yesterday.txt -u
# Using regex to extract keys
nin new-data.csv old-data.csv "^([^,]+)" -ui
# Switch positions to find what's in old but not in new
nin new-data.csv old-data.csv "^([^,]+)" -uiS# Unique lines from a file
nin access.log nul -u
# Unique IPs from log file
nin access.log nul "(\d+\.\d+\.\d+\.\d+)" -u
# Unique with whole line output (not just the key)
nin access.log nul "(\d+\.\d+\.\d+\.\d+)" -uw# Get top 20 most frequent errors
nin error.log nul "(\w*Exception)" -pd -H 20
# Get frequency of HTTP status codes
nin access.log nul "HTTP/\d\.\d\"\s+(\d+)" -pd--sum adds cumulative count and cumulative percentage to each output line.
Output format: [count]-[cumCount]([pct]%-[cumPct]%): [key]
nin error.log nul "^(\w+)" -pd --sum -C
# Output:
# 10-10(25.00%-25.00%): ExceptionTypeA
# 8-18(20.00%-45.00%): ExceptionTypeB
# 6-24(15.00%-60.00%): IllegalArgumentException
# 4-28(10.00%-70.00%): OutOfMemoryError
# 3-31( 7.50%-77.50%): SocketException
# 2-33( 5.00%-82.50%): NumberFormatException
# 2-35( 5.00%-87.50%): ExceptionTypeC
# Reading: "ExceptionTypeA: 10 times (25%), cumulative 10 (25% of all)"
# "After top 7 items: cumulative 35, covering 87.5% of all errors"# Exactly top 5 errors with cumulative coverage shown
nin error.log nul "^(\w+)" -pd --sum -H 5
# Shows: top 5 items + cumulative% at each step
# e.g. top 5 = 77.5% of all errors → helps answer "what % do my top 5 cover?"
# Get count without output (-H 0) for scripting
# PowerShell/CMD:
nin error.log nul "^(\w+)" -pd -H 0 2>nul
# Bash/zsh:
nin error.log nul "^(\w+)" -pd -H 0 2>/dev/null
# Exit code = total unique key count (12), no output → use in conditionals
# e.g. PowerShell: if ($LASTEXITCODE -gt 10) { "Too many error types!" }
-Jand sorting — critical interaction:
- Any sorting flag (
-p,-a,-d) forces full read: nin must collect all data before sorting, so-Jcannot early-exit. Exit code = total count (key count with-p/-u; row count with-a/-dalone).- No sorting flags (
-ualone, plain diff/intersection):-Jenables true early-exit after N lines. Exit code = N (lines actually output).-H 0: always outputs nothing; exit code = total count (works in all modes, useful for scripting).
-K P stops when the current item's own percentage drops below P%.
This automatically filters out the long tail without needing to guess N:
# Auto top-N: show only items with >= 5% individual frequency
nin error.log nul "^(\w+)" -pd --sum -K 5.0
# Result: 7 items shown covering 87.5% — items < 5% (long tail) suppressed
# More aggressive threshold: only top-tier items >= 7.5%
nin error.log nul "^(\w+)" -pd --sum -K 7.5
# Result: top 5 items (77.5% coverage) — clear major contributors
# Rule of thumb:
# -K 10.0 → major contributors only (>= 10% each)
# -K 5.0 → significant contributors (>= 5% each)
# -K 1.0 → meaningful contributors (>= 1% each)
-Kvs-H:-H Ngives exactly N items;-K Pgives a data-driven N based on item significance. Use-Kwhen you don't know N in advance. Use-Hwhen you need a fixed count (dashboards, reports).
-K+-Htogether:-Hacts as a hard cap.nin ... -pd --sum -K 5.0 -H 3shows at most 3 items (even if 7 meet the -K threshold).
# Only show items appearing 3+ times (ignore rare one-off errors)
nin error.log nul "^(\w+)" -pd --sum -k 3
# Stops when item count drops below 3 → only items with count >= 3 shown
# (In this example: top 5 items, covering 77.5%)# Show rare items first — understand what the long tail looks like
nin error.log nul "^(\w+)" -pa --sum
# Ascending order: rarest first, cumulative shows how much the tail represents
# e.g. 5 items each at 2.5% = 12.5% → "long tail contributes only 12.5%, safe to ignore"# Top exception types across all log files, auto-stop at 5%, with cumulative
msr -rp logs/ -f "\.log$" -t "(\w+Exception|\w+Error)\b" -PAC |
nin nul "^(\w+(?:Exception|Error))" -pd --sum -K 5.0 -H 20
# Top HTTP error codes with coverage
msr -rp logs/ -f "access\.log" -PAC |
nin nul "HTTP/\d\.\d\"\s+([45]\d\d)" -pd --sum -H 10
# Get just the count for CI/CD alerting (no output, use exit code)
nin error.log nul "^(\w+Exception)" -pd -H 0 2>nul
# Returns unique exception type count as exit code📖 More Pareto analysis examples: See Cumulative Pareto Analysis for real-world applications in log triage, capacity planning, and cost optimization.
The -wn flag combination filters structured files while preserving all comments and formatting. For the full explanation of -w, -n, and their interaction, see Output Control: -w and -n.
# Remove machines in remove-list from hosts file, keep all comments and structure
nin hosts-full.txt remove-list.txt "^(\S+)" "^(\S+)" -wn -PAC > hosts-updated.txt
# Keep only allowlisted machines (intersection + structure preservation)
nin hosts-full.txt allowlist.txt "^(\S+)" "^(\S+)" -mwn -PAC > hosts-allowed.txt
# Case-insensitive removal (WEB-03 matches web-03)
nin hosts-full.txt remove-list.txt "^(\S+)" "^(\S+)" -wni -PAC > hosts-updated.txt
# Multi-step pipeline: nin removes entries, msr filters by column
nin hosts.txt decommission-list.txt "^(\S+)" "^(\S+)" -wn -PAC |
msr -t "^\s*#|active$" -PAC > hosts-active-only.txt# Get file extension distribution (most common file types)
msr -rp . -l -PAC --xd -k 18 | nin nul "\.(\w+)$" -p -d
# Get top-level folder distribution
msr -rp . -l -PAC --xd -k 18 | nin nul "^([^\\/]+)[\\/]" -p -d
# Combined with msr for targeted analysis
msr -rp src/ -f "\.cs$" -l -PAC | nin nul "[\\/](\w+)\.cs$" -pd -H 20| Option | Meaning | Example |
|---|---|---|
| (default) | Difference set (not in latter) | nin a.txt b.txt |
-m |
Intersection (in both) | nin a.txt b.txt -m |
-u |
Unique (remove duplicates) | nin a.txt nul -u |
-S |
Switch file positions (swap roles) | nin a.txt b.txt -S |
These two flags control what is output for each line and are the most important output options:
Without -w, nin outputs only the captured key (capture group[1]).
With -w, nin outputs the full original line containing the key.
# Given file with: "name = Alpha", "name = Beta", "name = Gamma"
nin file.txt nul "name = (\w+)" -PAC # outputs: Alpha Beta Gamma
nin file.txt nul "name = (\w+)" -w -PAC # outputs: name = Alpha name = Beta name = GammaWithout -n, nin only outputs lines that matched the regex.
With -n, nin also outputs lines that did not match the regex (not-captured lines, e.g. comments, headers).
Rules for -n:
- Lines that matched → output the captured key (or whole line if
-wused) - Lines that did NOT match → output the whole not-captured line as-is
- Empty lines in file body → silently skipped (not output even with
-n); however, a trailing newline at end-of-file creates an empty-line entry that participates in unique counting and sorting (use-Zto skip it)
# Given file:
# # header comment
# name = Alpha
# name = Beta
# ; another comment
# name = Gamma
nin file.txt nul "name = (\w+)" -n -PAC
# outputs:
# # header comment ← not-captured line, output as-is
# Alpha ← captured key only
# Beta
# ; another comment ← not-captured line, output as-is
# GammaThis combination outputs whole lines for matched entries AND passes through all non-matched lines.
- Two-file mode +
-wn: structure-preserving filter — excludes items from file2 while preserving all comments, headers, and blank lines from file1. This is the primary use case for editing config/hosts files. - Single-file mode +
-wn: structure-preserving pass-through — outputs everything (no second file to diff against).
⚠️ -wn --nt(single-file) is a no-op:--ntexcluded lines are demoted to not-captured, then-nre-outputs them as-is. Use two-file mode-wn(with exclude list file) or-w --nt(without-n, loses blank lines) instead.
nin file.txt nul "name = (\w+)" -wn -PAC
# outputs the complete file (all 5 non-empty lines):
# # header comment
# name = Alpha
# name = Beta
# ; another comment
# name = Gamma
# Real use case: filter config while preserving comments and structure
nin my-config.ini exclude.txt "name = (\w+)" "(\w+)" -wn > filtered-config.ini
# Result: only excluded entries are removed, all comments and formatting preserved-S swaps the roles of file1 and file2 (and their respective regex patterns).
Without -S: outputs keys in file1 NOT in file2.
With -S: outputs keys in file2 NOT in file1 (effective reversal).
# config.ini has: Alpha, Beta, Gamma (+ comments)
# exclude.txt has: Alpha, BadEntry
nin config.ini exclude.txt "name = (\w+)" "(\w+)" -PAC
# outputs: Beta, Gamma (keys in config NOT in exclude)
nin config.ini exclude.txt "name = (\w+)" "(\w+)" -S -PAC
# outputs: BadEntry (keys in exclude NOT in config — the "bad" entries)By default, nin's summary line goes to stderr (so it doesn't pollute redirected output).
With -I, the summary goes to stdout — useful when you want the summary captured in a file or variable.
# Summary goes to stderr (default) — stdout redirect captures only data
nin error.log nul "(\w+Exception)" -pd -H 30 > report.txt
# report.txt has only data; summary appears on terminal
# Summary goes to stdout (-I) — both data and summary captured
nin error.log nul "(\w+Exception)" -pd -H 30 -I > report.txt
# report.txt has data + summary line
# Suppress stderr warnings while keeping stdout output
nin file.txt nul "(\w+)" -pd 2>nul
# Only warnings go to stderr; summary goes to stderr too (unless -I used)| Option | Meaning | Example |
|---|---|---|
-p |
Show percentages | -pd |
-P |
Hide percentages | -pdP |
-a |
Ascending sort | -pa |
-d |
Descending sort | -pd |
| Option | Meaning | Example |
|---|---|---|
-i |
Ignore case | -ui |
-t <regex> |
Keep only matched output lines matching regex (AND with -x) |
-t "Error" |
-x <text> |
Keep only matched output lines containing plain text (AND with -t) |
-x "Failed" |
--nt <regex> |
Exclude matched output lines matching regex | --nt "debug|trace" |
--nx <text> |
Exclude matched output lines containing plain text | --nx "maintenance" |
--enhance <regex> |
Color highlight only — never filters lines | --enhance "\d+" |
-H N |
Output first N lines | -H 20 |
-T N |
Output last N lines | -T 10 |
-k N |
Stop when item count drops below N (descending -pd) or exceeds N (ascending -pa) |
-pd -k 5 |
-K P |
Stop when current item's percentage < P% (per-item, NOT cumulative) | -pd -K 10.0 |
-tvs--enhance:-tand-xfilter which lines appear in output.--enhance(short:-e) only adds color and never removes lines. When both-tand-eare used, nin colors using the merged regex(-t)|-e— so both patterns are highlighted.
What do
-t/-x/--nt/--nxfilter against?
- Normal mode (no
-n): filters against the full original line- Without
-w: output still shows captured key only- With
-w: output shows whole line- With
-n: also output not-captured lines (comments, headers)- With
-w -n: output matched whole lines plus not-captured lines- Key distinction:
-wchanges output form (key vs whole line), not the normal-mode filter target
# Filter by machine name prefix (--nt matches against FULL original line, not captured key)
nin hosts.txt nul "^(\S+)" --nt "^web-" -PAC
# Removes lines starting with web- (^web- matches full line start)
# NOTE: --nt "^db-old$" would NOT work because $ doesn't match mid-line;
# use --nt "^db-old\b" or --nt "^db-old\s" instead
# Filter by STATUS COLUMN (status text is in the full line, not captured key)
nin hosts.txt nul "^(\S+)" -w --nt "maintenance|decommission" -PAC
# Removes lines containing 'maintenance' or 'decommission' anywhere in the line
# Comments survive (captured as '#'), blank lines lost (no -n)| Option | Meaning |
|---|---|
-PAC |
Pure output: no percent, no info, no color |
-PC |
No percent, no color (keeps summary) |
-M |
No summary |
-A |
No any info |
-I |
Route summary to stdout (default: stderr) |
--colors |
Set fore/back colors for -t/-e/-x and summary (see Color Customization) |
--keep-color |
Preserve ANSI colors when piping (Windows/MinGW) |
--unix-slash 1 |
Output forward slash / on Windows/MinGW/Cygwin |
--not-warn-bom |
Suppress BOM encoding warnings for non-UTF8 BOM files |
--to-stderr |
Output result to stderr instead of stdout |
--verbose |
Show parsed arguments, return value, time zone, BOM info, etc. |
nin keeps original line order by default (unless you use sorting options):
# Unique lines in original order
nin file.txt nul -u
# Unique lines sorted by frequency
nin file.txt nul -u -pdnin works great with msr for complex data processing:
# Extract unique paths from PATH variable
msr -z "%PATH%;" -t "\\*?\s*;\s*" -o "\n" -aPAC | nin nul "(\S+.+)" -ui
# Find duplicate paths with top 5 frequency
msr -z "%PATH%;" -t "\\*?\s*;\s*" -o "\n" -aPAC | nin nul "(\S+.+)" -iupd -H 5See the complete example in Common Use Cases — File Distribution Analysis (with msr).
See the complete example in Common Use Cases — Analyzing Distribution and Top-N.
See Return Values for shell-safe conditional examples.
See Common Use Cases — --sum: Pareto / cumulative analysis.
# Check useless imports in PowerShell scripts
msr -rp . -f "\.psm?1$" -t "^\s*Import-Module\s+(.+\.psm1)" -C -I -W | nin nul "Import-Module\s+(\S+)" -pd
# Check TypeScript imports for circular dependencies
msr -p file.ts -t "^\s*import\s+.*?from\s+'(\./.+?)';\s*$" -o "\1" -PAC
# Extract unique function/method calls
msr -rp . -f "\.cs$" -t "\.(\w+)\s*\(" -PAC | nin nul "(\w+)" -pd -H 50# File1 has "name = John", File2 has "John,Smith,30"
nin users.txt data.csv "name = (\w+)" "^(\w+),"
# Compare log errors vs known error list
nin error.log known-errors.txt "Error:\s*(\S+)" "^(\S+)$"# Save distribution report with summary
# -I sends summary line to stdout (not stderr), so it's captured in the redirect
nin error.log nul "(\w*Exception)" -pd -H 30 -I > error-report.txt
# Save just the data without extra info
nin error.log nul "(\w*Exception)" -pd -H 30 -PAC > errors-only.txtnin returns useful values for scripts:
| Scenario | Return Value |
|---|---|
| Default mode | Count of lines/keys in file1 NOT in file2 |
With -m |
Count of lines/keys in BOTH files |
| No matches | 0 |
| Error occurred | -1 (usually 255 on Linux/macOS, 127 on MinGW — not guaranteed) |
Note: The -1 error code is truncated by shells to 8 bits (255) or 7 bits (127 on some MinGW). The exact value depends on your shell environment.
Cross-platform exit code truncation: On non-Windows platforms, exit codes are truncated (8-bit max 255 on Linux/macOS; 7-bit max 127 on some MinGW), which can cause counts to wrap to 0. Use
--exit gt255-to-255to cap values, or parse the summary line for exact large counts. See Return Value Cross-Platform Behavior for full details.
# Bash/zsh: check if files differ
nin file1.txt file2.txt "^(\S+)" -H 0
if [ $? -eq 0 ]; then echo "Files have same keys"; fi
# PowerShell:
# nin expected.txt actual.txt -H 0
# if ($LASTEXITCODE -eq 0) { "Test passed" } else { "Found $LASTEXITCODE differences" }
# CMD:
# nin expected.txt actual.txt -H 0
# if %ERRORLEVEL% EQU 0 (echo Test passed) else (echo Found %ERRORLEVEL% differences)- Check if files exist and have content
- Verify your regex pattern captures what you expect
- Test pattern with simpler file first
- Add
-cto see the command line
- Use
-cto see the command being executed - Test regex capture with:
msr -z "test line" -t "\byourPattern\b" - Remember: capture group[1] is used as the key, not group[0]
- If no capture group, whole line is used as key
- Use
-Yif nin incorrectly reads from pipe - Recommended pipe form for single-stream analysis:
... | nin nul "(\w+)" -pd - If you need to compare pipe input against a second file:
... | nin file2.txt "(\w+)"
nin supports 8 encoding types with BOM auto-detection (same as msr). For the complete encoding matrix, BOM detection details, non-ASCII/Unicode handling, and platform-specific behavior, see msr and nin Shared Reference — Encoding Support.
Quick tips:
- BOM files are automatically detected; use
--not-warn-bomto suppress warnings - macOS/Linux: Non-ASCII characters (Chinese, Japanese, Korean, Emoji, etc.) in regex arguments work correctly — the terminal uses UTF-8 natively
- Windows: Non-ASCII characters in command-line arguments may be affected by terminal encoding (ANSI code page). On non-matching locale, use English patterns as workaround
nin shares 7 MSR_* environment variables with msr (MSR_NO_COLOR, MSR_COLORS, MSR_NOT_WARN_BOM, MSR_SKIP_LAST_EMPTY, MSR_KEEP_COLOR, MSR_UNIX_SLASH, MSR_EXIT). For the complete variable-to-parameter mapping table and usage examples, see msr and nin Shared Reference — Environment Variables.
# Example: suppress BOM warnings and disable color for all nin/msr commands in a script
export MSR_NOT_WARN_BOM=1
export MSR_NO_COLOR=1Tip: Set these temporarily (per script or session), not globally — global presets can cause unexpected behavior on other machines.
| Operation | Use nin | Use msr |
|---|---|---|
| Set difference | ✓ | |
| Set intersection | ✓ | |
| Unique/dedup | ✓ | |
| Distribution stats | ✓ | |
| File search | ✓ | |
| Text replacement | ✓ | |
| Block matching | ✓ | |
| Execute commands | ✓ |
Best Practice: Use msr for searching and replacing in files, use nin for set operations and distribution analysis.
📖 Detailed tool comparisons: See Tool Comparisons for comprehensive feature tables (msr vs grep/ripgrep/sed, nin vs comm/uniq/sort, and more).
The vscode-msr extension provides ready-to-use aliases that combine msr and nin for common tasks. See:
- vscode-msr User Guide — alias usage guide for humans
- vscode-msr AI Agent Reference — alias reference for AI agents
Related documentation in this project:
- nin AI Agent Reference — technical parameter reference for AI agents
- msr User Guide — text search and replace with msr
- msr AI Agent Reference — msr parameter reference for AI agents
- vscode-msr User Guide — alias usage guide for humans
- vscode-msr AI Agent Reference — alias reference for AI agents
- Use Cases and Comparisons — practical use cases, industry applications, and tool comparisons
- AI Agent Usage Guide — AI agent integration guide for msr, nin, and vscode-msr aliases
- Download Links — download tables for all platforms
External links:
- GitHub: https://github.com/qualiu/msr
- More tools: https://github.com/qualiu/msrTools
- VSCode extension: https://github.com/qualiu/vscode-msr
- Usage screenshots: https://qualiu.github.io/msr/usage-by-running/nin-Windows.html