Batch Files
A comprehensive skill for creating, editing, debugging, and maintaining Windows batch files (.bat/.cmd) using cmd.exe. Applies to CLI tool development, system administration automation, scheduled tasks, file operations scripting, and PATH-based executable scripts.
When to Use This Skill
- Creating or editing or files
- Automating Windows tasks (file operations, deployments, backups)
- Building CLI tools intended for a folder on PATH
- Writing scheduled task scripts (SCHTASKS, Task Scheduler)
- Debugging batch script issues (variable expansion, error levels, quoting)
- Integrating batch scripts with external tools (curl, git, Node.js, Python)
- Scaffolding new batch-based projects with structured templates
Prerequisites
- Windows NT-based OS (Windows 7 or later)
- cmd.exe (built-in)
- Optional: a directory on PATH for distributing scripts as commands
- Optional: PATHEXT configured to include (default on Windows)
Command Interpretation
cmd.exe processes each line through four stages in order:
- Variable substitution — tokens are replaced with environment variable values. – reference batch arguments. expands to all arguments.
- Quoting and escaping — Caret escapes special characters (). Quotation marks prevent interpretation of enclosed special characters. In batch files, yields a literal .
- Syntax parsing — Lines are split into pipelines (), compound commands (, , ), and parenthesized groups .
- Redirection — overwrites, appends, reads input, redirects stderr, merges stderr into stdout, discards output.
Variables
Environment Variables
bat
set _MY_VAR=Hello World
echo %_MY_VAR%
set _MY_VAR=
- with no arguments lists all variables
- lists variables starting with
- No spaces around — sets variable to
Special Variables
| Variable | Value |
|---|
| Current directory |
| System date (locale-dependent) |
| System time HH:MM:SS.mm |
| Pseudorandom number 0–32767 |
| Exit code of last command |
| Current user name |
| Current user profile path |
| / | Temporary file directory |
| Executable extensions list |
| Path to cmd.exe |
Scoping with SETLOCAL / ENDLOCAL
bat
setlocal
set _LOCAL_VAR=scoped value
endlocal
REM _LOCAL_VAR is no longer defined here
To return a value from a scoped block:
bat
endlocal & set _RESULT=%_LOCAL_VAR%
Delayed Expansion
Variables inside parenthesized blocks are expanded at parse time. Use delayed expansion for runtime evaluation:
bat
setlocal EnableDelayedExpansion
set _COUNT=0
for /l %%i in (1,1,5) do (
set /a _COUNT+=1
echo !_COUNT!
)
endlocal
- expands at execution time (delayed)
- expands at parse time (immediate)
Control Flow
Conditional Execution
bat
if exist "output.txt" echo File found
if not defined _MY_VAR echo Variable not set
if "%_STATUS%"=="ready" (echo Go) else (echo Wait)
if %ERRORLEVEL% neq 0 echo Command failed
Comparison operators:
,
,
,
,
,
. Use
for case-insensitive string comparison.
Compound Commands
bat
command1 & command2 & REM Always run both
command1 && command2 & REM Run command2 only if command1 succeeds
command1 || command2 & REM Run command2 only if command1 fails
FOR Loops
bat
REM Iterate over a set of values
for %%i in (alpha beta gamma) do echo %%i
REM Numeric range: start, step, end
for /l %%i in (1,1,10) do echo %%i
REM Files in a directory
for %%f in (*.txt) do echo %%f
REM Recursive file search
for /r %%f in (*.log) do echo %%f
REM Directories only
for /d %%d in (*) do echo %%d
REM Parse command output
for /f "tokens=1,2 delims=:" %%a in ('ipconfig ^| findstr "IPv4"') do echo %%b
REM Parse file lines
for /f "usebackq tokens=*" %%a in ("data.txt") do echo %%a
GOTO and Labels
bat
goto :main_logic
:usage
echo Usage: %~nx0 [options]
exit /b 1
:main_logic
echo Running main logic...
goto :eof
exits the current batch or subroutine. Labels start with
.
Command-Line Arguments
| Syntax | Value |
|---|
| Script name as invoked |
| – | Positional arguments |
| All arguments (unaffected by SHIFT) |
| Argument 1 with enclosing quotes removed |
| Full path of argument 1 |
| Drive letter of argument 1 |
| Path (without drive) of argument 1 |
| File name (no extension) of argument 1 |
| Extension of argument 1 |
| Drive and path of the batch file itself |
| File name with extension of the batch file |
| File size of argument 1 |
| Search PATH for argument 1 |
Argument Parsing Pattern
bat
:parse_args
if "%~1"=="" goto :args_done
if /i "%~1"=="--help" goto :usage
if /i "%~1"=="--output" (
set "_OUTPUT_DIR=%~2"
shift
)
shift
goto :parse_args
:args_done
String Processing
Substrings
bat
set _STR=Hello World
echo %_STR:~0,5% & REM "Hello"
echo %_STR:~6% & REM "World"
echo %_STR:~-5% & REM "World"
echo %_STR:~0,-6% & REM "Hello"
Search and Replace
bat
set _STR=Hello World
echo %_STR:World=Earth% & REM "Hello Earth"
echo %_STR:Hello=% & REM " World" (remove "Hello")
Substring Containment Test
bat
if not "%_STR:World=%"=="%_STR%" echo Contains "World"
Functions
Functions use labels, CALL, and SETLOCAL/ENDLOCAL:
bat
@echo off
call :greet "Jane Doe"
echo Result: %_GREETING%
exit /b 0
:greet
setlocal
set "_MSG=Hello, %~1"
endlocal & set "_GREETING=%_MSG%"
exit /b 0
- invokes a function
- returns from the function (not the script)
- Use the trick to pass values out of a scoped block
Arithmetic
performs 32-bit signed integer arithmetic:
bat
set /a _RESULT=10 * 5 + 3
set /a _COUNTER+=1
set /a _REMAINDER=14 %% 3 & REM Use %% for modulo in batch files
set /a _BITS="255 & 0x0F" & REM Bitwise AND
Supported operators:
and bitwise
.
Hexadecimal (
) and octal (
) literals are supported.
Error Handling
Error Level Conventions
- = success
- Non-zero = failure (typically )
bat
mycommand.exe
if %ERRORLEVEL% neq 0 (
echo ERROR: mycommand failed with code %ERRORLEVEL%
exit /b %ERRORLEVEL%
)
Fail-Fast Pattern
bat
command1 || (echo command1 failed & exit /b 1)
command2 || (echo command2 failed & exit /b 1)
Setting Exit Codes
bat
exit /b 0 & REM Return success from a batch/function
exit /b 1 & REM Return failure
cmd /c "exit /b 42" & REM Set ERRORLEVEL to 42 inline
Essential Commands Reference
File Operations
| Command | Purpose |
|---|
| List directory contents |
| Copy files |
| Extended copy with subdirectories (legacy) |
| Robust copy with retry, mirror, logging |
| Move or rename files |
| Delete files |
| Rename files |
| / | Create directories |
| / | Remove directories |
| Create symbolic or hard links |
| View or set file attributes |
| Print file contents |
| Paginated file display |
| Display directory structure |
| Replace files in destination with source |
| Show or set NTFS compression |
| Extract from .cab files |
| Create .cab archives |
| Create or extract tar archives |
Text Search and Processing
| Command | Purpose |
|---|
| Search for literal strings |
| Search with limited regular expressions |
| Sort lines alphabetically |
| Copy piped input to clipboard |
| Compare two files |
| Binary file comparison |
| Encode/decode Base64, compute hashes |
System Information
| Command | Purpose |
|---|
| Full system configuration |
| Display computer name |
| Windows version |
| Current user and group info |
| List running processes |
| Terminate processes |
| WMI queries (drives, OS, memory) |
| Service control (query, start, stop) |
| List installed drivers |
| Registry operations (query, add, delete) |
| Set persistent environment variables |
Network
| Command | Purpose |
|---|
| Test network connectivity |
| IP configuration |
| DNS lookup |
| Network connections and ports |
| Trace route to host |
| Map/disconnect network drives |
| Manage user accounts |
| Network configuration utility |
| ARP cache management |
| Routing table management |
| HTTP requests (Windows 10+) |
| Secure shell (Windows 10+) |
Scheduling and Automation
| Command | Purpose |
|---|
| Create and manage scheduled tasks |
| Wait N seconds (Vista+) |
| Launch programs asynchronously |
| Run as different user |
| Shutdown or restart |
| Find files by date and execute commands |
Shell Utilities
| Command | Purpose |
|---|
| Locate executables in PATH |
| Create command macros |
| Prompt for single-key input |
| Configure console size and ports |
| Map folder to drive letter |
| Get or set console code page |
| Set console colors |
| Set console window title |
| / | File type associations |
Shell Syntax and Expressions
Parentheses for Grouping
Parentheses turn compound commands into a single unit for redirection or conditional execution:
bat
(echo Line 1 & echo Line 2) > output.txt
if exist "data.csv" (
echo Processing...
call :process "data.csv"
) else (
echo No data found.
)
Escape Characters
The caret
escapes the next character:
bat
echo Total ^& Summary & REM Outputs: Total & Summary
echo 100%% complete & REM Outputs: 100% complete (in batch)
echo Line one^
Line two & REM Caret escapes the newline
After a pipe, triple caret is needed:
echo x ^^^& y | findstr x
Wildcards
- matches any sequence of characters
- matches a single character (or zero at end of period-free segment)
bat
dir *.txt & REM All .txt files
ren *.jpeg *.jpg & REM Bulk rename
Redirection Summary
bat
command > file.txt & REM Overwrite stdout to file
command >> file.txt & REM Append stdout to file
command 2> errors.log & REM Redirect stderr
command > all.log 2>&1 & REM Merge stderr into stdout
command < input.txt & REM Read stdin from file
command > NUL 2>&1 & REM Discard all output
Writing Production-Quality Batch Files
Standard Script Structure
bat
@echo off
setlocal EnableDelayedExpansion
REM ============================================================
REM Script: example.bat
REM Purpose: Describe what this script does
REM ============================================================
call :main %*
exit /b %ERRORLEVEL%
:main
call :parse_args %*
if not defined _TARGET (
echo ERROR: --target is required. 1>&2
call :usage
exit /b 1
)
echo Processing: %_TARGET%
exit /b 0
:parse_args
if "%~1"=="" exit /b 0
if /i "%~1"=="--target" set "_TARGET=%~2" & shift
if /i "%~1"=="--help" call :usage & exit /b 0
shift
goto :parse_args
:usage
echo Usage: %~nx0 --target ^<path^> [--help]
echo.
echo Options:
echo --target Path to process (required)
echo --help Show this help message
exit /b 0
Best Practices
- Always start with and — Prevents noisy output and variable leakage to the caller.
- Validate inputs before processing — Check required arguments and file existence early. Use and .
- Quote paths and variables — Use and to handle spaces and special characters safely.
- Use instead of — Avoids closing the parent console window.
- Return meaningful exit codes — for success, non-zero for specific failures.
- Use for script-relative paths — Ensures the script works regardless of the caller's working directory.
- Prefer over — More reliable, supports retry, mirroring, and logging.
- Use when modifying variables inside loops or parenthesized blocks.
- Write errors to stderr — keeps stdout clean for piping.
- Use for comments — can cause issues inside loop bodies.
Security Considerations
- Never store credentials in batch files — Use environment variables, credential stores, or prompts.
- Validate user input — Unquoted variables containing , , or can inject commands. Always quote: .
- Use — Prevents variable values from leaking to parent processes.
- Sanitize file paths — Validate paths before passing to , , or to prevent unintended deletion.
- Avoid for sensitive input — Input is visible and stored in console history. Use a dedicated credential tool when possible.
Debugging and Troubleshooting
| Technique | How |
|---|
| Trace execution | Remove or use temporarily |
| Step through | Add between sections |
| Check error level | echo Exit code: %ERRORLEVEL%
after each command |
| Inspect variables | to list all variables starting with |
| Delayed expansion issues | Variable inside block not updating? Enable syntax |
| FOR loop vs | Use in batch files, on the command line |
| Spaces in SET | not |
| Caret in pipes | After a pipe, use to escape special chars |
| Parentheses in SET /A | Escape with and inside blocks, or use quotes |
| Double percent for modulo | in batch files |
Cross-Platform and Extended Tools
When batch scripting reaches its limits, these tools extend cmd.exe capabilities:
| Tool | Purpose |
|---|
| Cygwin | Full POSIX environment on Windows (grep, sed, awk, ssh) |
| MSYS2 | Lightweight Unix tools and package manager (pacman) |
| WSL | Windows Subsystem for Linux — run native Linux binaries |
| GnuWin32 | Individual GNU utilities as native Windows executables |
| PowerShell | Modern Windows scripting with .NET integration |
Use batch when you need: fast startup, simple file operations, PATH-based CLI tools, or Task Scheduler integration. Consider PowerShell or WSL for complex data processing, REST APIs, or object-oriented scripting.
CMD Keyboard Shortcuts
| Shortcut | Action |
|---|
| Auto-complete file/folder names |
| / | Navigate command history |
| Show command history popup |
| Repeat last command |
| Clear current line |
| Cancel running command |
| Clear command history |
Reference Files
The
folder contains detailed documentation:
| File | Contents |
|---|
| Windows tools, utilities, package managers, terminals |
batch-files-and-functions.md
| Example scripts, techniques, best practices links |
| Comprehensive A-Z Windows command reference |
| Cygwin user guide and FAQ |
| MSYS2 installation, packages, and environments |
windows-subsystem-on-linux.md
| WSL setup, commands, and documentation |
Asset Templates
The
folder contains starter batch file template data, but as text files:
| Template | Purpose |
|---|
| Standalone CLI tool with argument parsing |
| Reusable function library with CALL-able labels |
| Scheduled task / automation script |