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 invoke
- "Create or edit a
.bator.cmdfile." - "Automate a Windows task with cmd.exe."
- "Build a batch CLI tool for a
bin/folder on PATH." - "Write a scheduled task script for SCHTASKS or Task Scheduler."
- "Debug batch variable expansion, error levels, or quoting."
- "Integrate a batch script with curl, git, Node.js, or Python."
- "Scaffold a batch-based project from templates."
Prerequisites and context
- Windows NT-based OS (Windows 7 or later)
- cmd.exe (built-in)
- Optional: a
bin/directory on PATH for distributing scripts as commands - Optional: PATHEXT configured to include
.BAT;.CMD(default on Windows)
Command Interpretation
cmd.exe processes each line through four stages in order:
- Variable substitution —
%VAR%tokens are replaced with environment variable values.%0–%9reference 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,2>redirects stderr,2>&1merges stderr into stdout,>NULdiscards output.
Variables
Environment Variables
set _MY_VAR=Hello World
echo %_MY_VAR%
set _MY_VAR=
setwith no arguments lists all variablesset _PREFIXlists variables starting with_PREFIX- No spaces around
=—set name = valsets variable"name "to" val"
Special Variables
| Variable | Value |
|---|---|
%CD% |
Current directory |
%DATE% |
System date (locale-dependent) |
%TIME% |
System time HH:MM:SS.mm |
%RANDOM% |
Pseudorandom number 0–32767 |
%ERRORLEVEL% |
Exit code of last command |
%USERNAME% |
Current user name |
%USERPROFILE% |
Current user profile path |
%TEMP% / %TMP% |
Temporary file directory |
%PATHEXT% |
Executable extensions list |
%COMSPEC% |
Path to cmd.exe |
Scoping with SETLOCAL / ENDLOCAL
setlocal
set _LOCAL_VAR=scoped value
endlocal
REM _LOCAL_VAR is no longer defined here
To return a value from a scoped block:
endlocal & set _RESULT=%_LOCAL_VAR%
Delayed Expansion
Variables inside parenthesized blocks are expanded at parse time. Use delayed expansion for runtime evaluation:
setlocal EnableDelayedExpansion
set _COUNT=0
for /l %%i in (1,1,5) do (
set /a _COUNT+=1
echo !_COUNT!
)
endlocal
!VAR!expands at execution time (delayed)%VAR%expands at parse time (immediate)
Control Flow
Conditional Execution
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: equ, neq, lss, leq, gtr, geq. Use /i for case-insensitive string comparison.
Compound Commands
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
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
goto :main_logic
:usage
echo Usage: %~nx0 [options]
exit /b 1
:main_logic
echo Running main logic...
goto :eof
goto :eof exits the current batch or subroutine. Labels start with :.
Command-Line Arguments
| Syntax | Value |
|---|---|
%0 |
Script name as invoked |
%1–%9 |
Positional arguments |
%* |
All arguments (unaffected by SHIFT) |
%~1 |
Argument 1 with enclosing quotes removed |
%~f1 |
Full path of argument 1 |
%~d1 |
Drive letter of argument 1 |
%~p1 |
Path (without drive) of argument 1 |
%~n1 |
File name (no extension) of argument 1 |
%~x1 |
Extension of argument 1 |
%~dp0 |
Drive and path of the batch file itself |
%~nx0 |
File name with extension of the batch file |
%~z1 |
File size of argument 1 |
%~$PATH:1 |
Search PATH for argument 1 |
Argument Parsing Pattern
: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
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
set _STR=Hello World
echo %_STR:World=Earth% & REM "Hello Earth"
echo %_STR:Hello=% & REM " World" (remove "Hello")
Substring Containment Test
if not "%_STR:World=%"=="%_STR%" echo Contains "World"
Functions
Functions use labels, CALL, and SETLOCAL/ENDLOCAL:
@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
call :label argsinvokes a functionexit /breturns from the function (not the script)- Use the
endlocal & settrick to pass values out of a scoped block
Arithmetic
set /a performs 32-bit signed integer arithmetic:
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 (0xFF) and octal (077) literals are supported.
Error Handling
Error Level Conventions
0= success- Non-zero = failure (typically
1)
mycommand.exe
if %ERRORLEVEL% neq 0 (
echo ERROR: mycommand failed with code %ERRORLEVEL%
exit /b %ERRORLEVEL%
)
Fail-Fast Pattern
command1 || (echo command1 failed & exit /b 1)
command2 || (echo command2 failed & exit /b 1)
Setting Exit Codes
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
Progressive disclosure and bundled resources
- Batch command reference and production guidance — For command syntax tables, production hardening, troubleshooting, or cross-platform notes, consult this reference.
Reference files
The references/ folder contains detailed documentation:
| File | Contents |
|---|---|
tools-and-resources.md |
Windows tools, utilities, package managers, terminals |
batch-files-and-functions.md |
Example scripts, techniques, best practices links |
windows-commands.md |
Comprehensive A-Z Windows command reference |
cygwin.md |
Cygwin user guide and FAQ |
msys2.md |
MSYS2 installation, packages, and environments |
windows-subsystem-on-linux.md |
WSL setup, commands, and documentation |
Asset templates
The assets/ folder contains starter batch file template data, but as text files:
| Template | Purpose |
|---|---|
executable.txt |
Standalone CLI tool with argument parsing |
library.txt |
Reusable function library with CALL-able labels |
task.txt |
Scheduled task / automation script |
Output template
## Batch file result
**Status:** created | updated | reviewed | blocked
**Files:** `<script.bat or script.cmd>`
**Target shell:** `cmd.exe`
### Script contract
| Area | Decision | Evidence |
| --- | --- | --- |
| Arguments | `%0`, `%1`-`%9`, `%*`, `SHIFT`, `%~dp0` | <summary> |
| Variables | `%VAR%` immediate, `!VAR!` delayed, `setlocal`/`endlocal` | <summary> |
| Control flow | `if`, `for`, `goto :eof`, `call :label` | <summary> |
| Error handling | `%ERRORLEVEL%`, `&&`, `||`, `exit /b` | <summary> |
| Redirection | `>`, `>>`, `<`, `2>`, `2>&1`, `>NUL` | <summary> |
### Validation
- Syntax reviewed for quoting, escaping, and delayed expansion: pass | fail
- Exit codes propagate correctly: pass | fail
- Paths with spaces are quoted: pass | fail
Quality gate
- The script targets Windows
cmd.exeand uses.bator.cmdconventions. - Variables use
set "NAME=value"style where quoting matters and avoid spaces around=. - Parenthesized blocks use
setlocal EnableDelayedExpansionand!VAR!when runtime values are needed. - Arguments are read with
%~1,%~f1,%~dp0,%~nx0,%*, orSHIFTas appropriate. -
forvariables use%%iin batch files and escape piped commands with^|insidefor /f. - Paths and user inputs are quoted to survive spaces and special characters.
- Failures return non-zero
exit /bcodes and preserve meaningful%ERRORLEVEL%. - Bundled
references/andassets/files are consulted only when their deeper detail or template content is needed.