Skip to main content

Blinter

Supported Python versions PyPI Downloads (month) OpenSSF Best Practices

Blinter is a linter for Windows batch files (.bat and .cmd). It provides comprehensive static analysis to identify syntax errors, security vulnerabilities, performance issues and style problems. Blinter helps you write safer, more reliable and maintainable batch scripts.

  • ✅ Configurable Options - Configurable rules, --verbose/--quiet logging, robust error handling
  • ✅ Unicode Support - Support for international characters and filenames
  • ✅ Performance Optimized - Handles large batch files efficiently

Features ✨

🔍 Rule Categories

  • Built-in Rules -- the registry currently ships 191 rules across 5 severity levels (see blinter.rules.registry.RULE_COUNT)
  • Error Level (E001-E999): Critical syntax errors that prevent execution
  • Warning Level (W001-W999): Potential runtime issues and bad practices
  • Style Level (S001-S999): Code formatting and readability improvements
  • Security Level (SEC001+): Security vulnerabilities and dangerous operations
  • Performance Level (P001-P999): Optimization opportunities and efficiency improvements

📖 For complete rule descriptions with examples and implementation details, see Batch-File-Linter-Requirements.md

📋 Output Format

  • Rule Codes: Each issue has a unique identifier (e.g., E002, W005, SEC003)
  • Clear Explanations: Detailed descriptions of why each issue matters
  • Actionable Recommendations: Specific guidance on how to fix problems
  • Line-by-Line Analysis: Precise location of every issue
  • Context Information: Additional details about detected problems

🚀 Advanced Analysis

  • Static Code Analysis: Detects unreachable code and logic errors
  • Advanced Variable Expansion: Validates percent-tilde syntax (%~n1), string operations, and SET /A arithmetic
  • Command-Specific Validation: FOR loop variations, IF statement best practices, deprecated command detection
  • Variable Tracking: Identifies undefined variables and unsafe usage patterns
  • Security Scanning: Path traversal attacks, command injection risks, unsafe temp file creation
  • Performance Optimization: DIR flag optimization, unnecessary output detection, string operation efficiency
  • Cross-Platform Batch Compatibility: Warns about Windows version issues and deprecated commands in batch scripts
  • Large File Handling: Efficiently processes large batch files, with a warning when a file exceeds 10MB and a hard reject above 50MB
  • Robust Encoding Detection: Automatic detection via charset_normalizer, with nine built-in fallbacks (UTF-8, UTF-8 BOM, UTF-16, UTF-32, Latin-1, ASCII, CP437, CP850, CP1252)
  • Advanced Escaping Techniques: Validates caret escape sequences, multilevel escaping, and continuation characters
  • Professional FOR Command Analysis: Checks for usebackq, proper tokenizing, delimiters, and skip options
  • Process Management Best Practices: Timeout command usage, process verification, and restart patterns
  • Enhanced Security Patterns: User input validation, temporary file security, and self-modification detection

Installation 🛠️

Option 1: Install via pip (Recommended)

pip install Blinter

Option 2: Install via uv

uv tool install Blinter

Run without installing:

uvx blinter

Option 3: Standalone executable (no Python)

If you prefer a standalone .exe over pip, use the one-line installer:

curl -L https://raw.githubusercontent.com/BatchLang/Blinter/main/scripts/install_blinter.cmd -o install_blinter.cmd && (call install_blinter.cmd || cd .) && del install_blinter.cmd

This installs the latest blinter.exe to %LOCALAPPDATA%\Programs\Blinter\bin, adds it to your user PATH, and handles updates automatically. Restart your terminal or IDE after installation for PATH changes to take effect.

Manual zip download (fallback):

  • Download the latest Blinter-v1.x.x.zip from GitHub Releases
  • Extract the archive; the executable is Blinter-v1.x.x\blinter.exe
  • The one-line installer above is preferred; it keeps blinter on your PATH without manual setup.
  • ⚠️ Note: Some antivirus software may flag the standalone executable as a false positive. The executable is completely safe (all source code is open for inspection). If a scanner flags it, use pip installation.

Uninstall

Standalone executable (one-line installer):

curl -L https://raw.githubusercontent.com/BatchLang/Blinter/main/scripts/uninstall_blinter.cmd -o uninstall_blinter.cmd && (call uninstall_blinter.cmd || cd .) && del uninstall_blinter.cmd

pip installation:

pip uninstall Blinter

uv installation:

uv tool uninstall Blinter

Prerequisites

  • Python 3.11+ (required for pip installation and development; uv can provision this interpreter)
  • Windows OS (64-bit required for the standalone executable)

Usage 📟

Basic Usage

If installed via pip or uv:

# Analyze a single batch file
blinter script.bat
# or
python -m blinter script.bat

# Analyze all batch files in a directory (recursive)
python -m blinter /path/to/batch/files

# Analyze batch files in directory only (non-recursive)
python -m blinter /path/to/batch/files --no-recursive

# Analyze with summary
python -m blinter script.bat --summary

# Analyze script and scripts it calls with shared variable context
python -m blinter script.bat --follow-calls

# Analyze with custom maximum line length
python -m blinter script.bat --max-line-length 120

# Create configuration file
python -m blinter --create-config

# Ignore configuration file
python -m blinter script.bat --no-config

# Get help
python -m blinter --help

# Get version
python -m blinter --version

If using standalone executable (installer or manual download):

# After the one-line installer, use blinter on PATH.
# Manual zip: run Blinter-v1.x.x\blinter.exe or add that folder to PATH.

# Analyze a single batch file
blinter script.bat

# Analyze all batch files in a directory (recursive)
blinter /path/to/batch/files

# Analyze batch files in directory only (non-recursive)
blinter /path/to/batch/files --no-recursive

# Analyze with summary
blinter script.bat --summary

# Analyze script and scripts it calls with shared variable context
blinter script.bat --follow-calls

# Analyze with custom maximum line length
blinter script.bat --max-line-length 120

# Get help
blinter --help

# Get version
blinter --version

Command Line Options

  • <path>: Path to a batch file (.bat or .cmd) OR directory containing batch files
  • --summary: Display summary statistics of issues found
  • --max-line-length <n>: Set maximum line length for S011 and S020 rules (default: 100)
  • --no-recursive: When processing directories, only analyze files in the specified directory (not subdirectories)
  • --follow-calls: Automatically analyze scripts called by CALL statements and merge their variable context. When enabled, variables defined in called scripts (including transitively called scripts within depth and file limits) are recognized as "defined" in the calling script (position-aware: only after the CALL statement). This eliminates false positive undefined variable errors for configuration scripts
  • --config <path>: Load settings from a custom configuration file instead of blinter.ini in the current directory
  • --no-config: Don't use configuration file (blinter.ini) even if it exists
  • --create-config: Create a default blinter.ini configuration file and exit
  • --create-config --force: Overwrite an existing blinter.ini when creating the default configuration
  • --output <path>: Write a structured JSON lint report to the given file path (human-readable output is unchanged unless --format json is also set)
  • --format json: Suppress human-readable stdout and emit JSON (to stdout, or only to --output when both flags are used)
  • --verbose: Show detailed debug logging on stderr (DEBUG level)
  • --quiet: Suppress non-error logging output (ERROR level only)
  • --help: Show help menu and rule categories
  • --version: Display version information

Note: Command line options override configuration file settings. Blinter automatically looks for blinter.ini in the current directory.

Configuration File Options 📝

Section Setting Description Default
[general] recursive Search subdirectories when analyzing folders true
[general] show_summary Display summary statistics after analysis false
[general] max_line_length Maximum line length for S011 and S020 rules 100
[general] max_scan_files Maximum batch files to scan in a directory 1000
[general] follow_calls Analyze scripts called by CALL statements with shared variable context false
[general] min_severity Minimum severity level to report None (all)
[rules] enabled_rules Comma-separated list of rules to enable exclusively None (all enabled)
[rules] disabled_rules Comma-separated list of rules to disable None

Configuration notes:

  • When both enabled_rules and disabled_rules are set, a rule must appear in enabled_rules to run; disabled_rules then removes matches from that allowlist.
  • max_line_length in blinter.ini controls style rules S011/S020 (default 100). The hard read limit for individual lines is 10,000 characters (MAX_LINE_LENGTH in the engine); lines longer than that are rejected before linting.

Command Line Override

Command line options always override configuration file settings:

# Use config file settings
python -m blinter myscript.bat

# Override config to show summary
python -m blinter myscript.bat --summary

# Analyze script and scripts it calls with shared variable context
python -m blinter myscript.bat --follow-calls

# Override config with custom line length
python -m blinter myscript.bat --max-line-length 100

# Ignore config file completely
python -m blinter myscript.bat --no-config

# Write JSON report to a file (human-readable output unchanged)
python -m blinter myscript.bat --output report.json

# Machine-readable JSON on stdout only
python -m blinter myscript.bat --format json

# JSON file only, no human-readable stdout
python -m blinter project\\scripts --output results.json --format json

🔕 Inline Suppression Comments

You can suppress specific linter warnings directly in your batch files using special comments:

Suppress Next Line

REM LINT:IGNORE E009
ECHO '' .... Represents a " character

Suppress Current Line

REM LINT:IGNORE-LINE S013

Suppress Multiple Rules

REM LINT:IGNORE E009, W011, S004
ECHO Unmatched quotes "

Suppress All Rules on Line

REM LINT:IGNORE
REM This line and the next will be ignored for all rules

Supported formats:

  • REM LINT:IGNORE <code> - Suppress specific rule(s) on the next line
  • REM LINT:IGNORE - Suppress all rules on the next line
  • REM LINT:IGNORE-LINE <code> - Suppress specific rule(s) on the same line
  • REM LINT:IGNORE-LINE - Suppress all rules on the same line
  • :: LINT:IGNORE <code> - Alternative comment syntax (also supported)

Use cases:

  • Suppress false positives that can't be fixed
  • Ignore intentional deviations from best practices
  • Handle edge cases in documentation or help text
  • Temporarily ignore issues during development

🐍 Programmatic API Usage

Blinter exposes a small public API from the top-level blinter package:

from blinter import (
    BlinterConfig,
    RuleSeverity,
    lint_batch_file,
    load_config,
)

# Basic usage
issues = lint_batch_file("script.bat")
for issue in issues:
    print(f"Line {issue.line_number}: {issue.rule.name} ({issue.rule.code})")

# With custom configuration
config = BlinterConfig(
    max_line_length=80,
    disabled_rules={"S007", "S011"},
    min_severity=RuleSeverity.WARNING,
)
issues = lint_batch_file("script.bat", config=config)

# Process results
for issue in issues:
    print(f"Line {issue.line_number}: {issue.rule.name}")
    print(f"  {issue.rule.explanation}")
    print(f"  Fix: {issue.rule.recommendation}")

# Thread-safe design allows safe concurrent usage
from concurrent.futures import ThreadPoolExecutor

files = ["script1.bat", "script2.cmd", "script3.bat"]
with ThreadPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(lint_batch_file, files))

🔧 Configuration Options (BlinterConfig)

Parameter Type Default Description
recursive bool True Search subdirectories when linting a folder
show_summary bool False Show summary statistics in CLI output
max_line_length int 100 Maximum line length for S011 and S020 rules
max_scan_files int 1000 Maximum batch files to scan in a directory
follow_calls bool False Lint scripts referenced by CALL statements
scan_root str | None None Root path for --follow-calls containment (CLI sets automatically)
enabled_rules Set[str] empty If non-empty, only these rule codes run
disabled_rules Set[str] empty Rule codes to skip
min_severity RuleSeverity | None None Minimum severity to report (via blinter.ini; no dedicated CLI flag)

Supported File Types

  • .bat files (traditional batch files)
  • .cmd files (recommended for modern Windows)
  • Unicode filenames and international characters supported
  • Large files handled efficiently, with a warning above 10MB and a hard reject above 50MB

📁 Directory Processing

Blinter can analyze entire directories of batch files with powerful options:

  • Recursive Analysis: Automatically finds and processes all .bat and .cmd files in directories and subdirectories
  • Non-Recursive Mode: Use --no-recursive to analyze only files in the specified directory
  • Batch Processing: Handles multiple files efficiently with consolidated reporting
  • Error Resilience: Continues processing other files even if some files have encoding or permission issues
  • Progress Tracking: Shows detailed results for each file plus combined summary statistics

Examples:

# Pip installation:
blinter ./my-batch-scripts                 # Analyze all files recursively
blinter . --no-recursive                   # Current directory only
blinter ./scripts --summary               # With summary statistics

# Standalone executable (installer or manual zip):
blinter ./my-batch-scripts            # Analyze all files recursively
blinter . --no-recursive              # Current directory only
blinter ./scripts --summary           # With summary statistics

# Manual zip only (extract first):
Blinter-v1.x.x\blinter.exe ./my-batch-scripts

🔥 Integration Example

CI/CD Integration

# Example GitHub Actions workflow
- name: Lint Batch Files
  run: |
    python -c "
    from blinter import lint_batch_file
    from blinter import RuleSeverity
    import sys
    issues = lint_batch_file('deploy.bat')
    fatal = [i for i in issues if i.rule.severity in (RuleSeverity.ERROR, RuleSeverity.SECURITY)]
    if fatal:
        print(f'Found {len(fatal)} critical issues (errors or security)!')
        sys.exit(1)
    print(f'Batch file passed with {len(issues)} total issues')
    "

The blinter CLI exit codes:

Code Meaning
0 Success: no Error or Security findings, and every discovered primary file was processed
1 Lint failure: any Error or Security finding, CLI/path errors, no processable files, any skipped primary target files, or all discovered files failed to read
2 Unexpected internal error

Warnings and style issues alone do not fail the run when exit code would otherwise be 0.

Special thanks go out to BrainWaveCC for all the help bug hunting.

License 📄

This project is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later) — see COPYING for details.

Icon by Acidmit · Flaticon

PyPI Downloads (total)

Release files for Blinter 1.1.31

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for Blinter 1.1.31
File Size Uploaded
blinter-1.1.31.tar.gz 288.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for Blinter 1.1.31
File Interpreter ABI Platform
blinter-1.1.31-py3-none-any.whl Python 3 none any Details

Total release size: 474.6 kB

Release files / blinter-1.1.31.tar.gz

Download URL blinter-1.1.31.tar.gz
Size 288.2 kB
Tags Source
SHA-256 checksum
How to use checksums
f1694b90fe06ae9cbc2315c5748079c72a214a537d40c3dbce7f6a92a5789315
BLAKE2b-256 checksum
How to use checksums
8d0e17c6e04827d8ffd8f4624ca9dba6e7d5554d91b70133400d46561828a2ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / blinter-1.1.31-py3-none-any.whl

Download URL blinter-1.1.31-py3-none-any.whl
Size 186.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
de18329b68451b8dee2741d78211bf571e0329ae2a60a1a11268267ea44e3ff4
BLAKE2b-256 checksum
How to use checksums
be794a5cdc8cd22cf71d494be8e746011b26a427621d50ed63de306cb923c289
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

1.1.31 This release

2 release files

1.1.30

2 release files

1.1.29

2 release files

1.1.28

2 release files

1.1.21

2 release files

1.1.20

2 release files

1.1.19

2 release files

1.1.18

2 release files

1.1.17

2 release files

1.1.16

2 release files

1.1.15

2 release files

1.1.14

2 release files

1.1.13

2 release files

1.1.12

2 release files

1.1.11

2 release files

1.1.10

2 release files

1.1.9

2 release files

1.1.8

2 release files

1.1.7

2 release files

1.1.6

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.94

2 release files

1.0.93

2 release files

1.0.92

2 release files

1.0.90

2 release files

1.0.89

2 release files

1.0.88

2 release files

1.0.87

2 release files

1.0.86

2 release files

1.0.85

2 release files

1.0.84

2 release files

1.0.83

2 release files

1.0.82

2 release files

1.0.81

2 release files

1.0.80

2 release files

1.0.79

2 release files

1.0.78

2 release files

1.0.77

2 release files

1.0.76

2 release files

1.0.75

2 release files

1.0.74

2 release files

1.0.73

2 release files

1.0.72

2 release files

1.0.71

2 release files

1.0.70

2 release files

1.0.69

2 release files

1.0.68

2 release files

1.0.67

2 release files

1.0.66

2 release files

1.0.65

2 release files

1.0.64

2 release files

1.0.63

2 release files

1.0.62

2 release files

1.0.61

2 release files

1.0.60

2 release files

1.0.59

2 release files

1.0.58

2 release files

1.0.57

2 release files

1.0.56

2 release files

1.0.55

2 release files

1.0.54

2 release files

1.0.53

2 release files

1.0.52

2 release files

1.0.51

2 release files

1.0.50

2 release files

1.0.49

2 release files

1.0.48

2 release files

1.0.47

2 release files

1.0.46

2 release files

1.0.45

2 release files

1.0.15

2 release files

1.0.14

2 release files

1.0.13

2 release files

1.0.12

2 release files

1.0.11

2 release files

1.0.10

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page