Expert-level Windows batch file (.bat/.cmd) skill for writing, debugging, and maintaining CMD scripts. Use when asked to "create a batch file", "write a .bat script", "automate a Windows task", "CMD scripting", "batch automation", "scheduled task script", "Windows shell script", or when working with .bat/.cmd files in the workspace. Covers cmd.exe syntax, environment variables, control flow, string processing, error handling, and integration with system tools.
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.
.bat or .cmd filesbin/ folder on PATHbin/ directory on PATH for distributing scripts as commands.BAT;.CMD (default on Windows)cmd.exe processes each line through four stages in order:
%VAR% tokens are replaced with environment variable values. %0–%9 reference batch arguments. %* expands to all arguments.^ escapes special characters (& | < > ^). Quotation marks prevent interpretation of enclosed special characters. In batch files, %% yields a literal %.|), compound commands (&, &&, ||), and parenthesized groups ( ).> overwrites, >> appends, < reads input, 2> redirects stderr, 2>&1 merges stderr into stdout, >NUL discards output.set _MY_VAR=Hello World
echo %_MY_VAR%
set _MY_VAR=
set with no arguments lists all variablesset _PREFIX lists variables starting with _PREFIX= — set name = val sets variable "name " to " val"| 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 |
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%
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)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.
command1 & command2 & REM Always run both
command1 && command2 & REM Run command2 only if command1 succeeds
command1 || command2 & REM Run command2 only if command1 fails
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 :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 :.
| 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 |
: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
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"
set _STR=Hello World
echo %_STR:World=Earth% & REM "Hello Earth"
echo %_STR:Hello=% & REM " World" (remove "Hello")
if not "%_STR:World=%"=="%_STR%" echo Contains "World"
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 args invokes a functionexit /b returns from the function (not the script)endlocal & set trick to pass values out of a scoped blockset /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.
0 = success1)mycommand.exe
if %ERRORLEVEL% neq 0 (
echo ERROR: mycommand failed with code %ERRORLEVEL%
exit /b %ERRORLEVEL%
)
command1 || (echo command1 failed & exit /b 1)
command2 || (echo command2 failed & exit /b 1)
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
| Command | Purpose |
|---|---|
DIR | List directory contents |
COPY | Copy files |
XCOPY | Extended copy with subdirectories (legacy) |
ROBOCOPY | Robust copy with retry, mirror, logging |
MOVE | Move or rename files |
DEL | Delete files |
REN | Rename files |
MD / MKDIR | Create directories |
RD / RMDIR | Remove directories |
MKLINK | Create symbolic or hard links |
ATTRIB | View or set file attributes |
TYPE | Print file contents |
MORE | Paginated file display |
TREE | Display directory structure |
REPLACE | Replace files in destination with source |
COMPACT | Show or set NTFS compression |
EXPAND | Extract from .cab files |
MAKECAB | Create .cab archives |
TAR | Create or extract tar archives |
| Command | Purpose |
|---|---|
FIND | Search for literal strings |
FINDSTR | Search with limited regular expressions |
SORT | Sort lines alphabetically |
CLIP | Copy piped input to clipboard |
FC | Compare two files |
COMP | Binary file comparison |
CERTUTIL | Encode/decode Base64, compute hashes |
| Command | Purpose |
|---|---|
SYSTEMINFO | Full system configuration |
HOSTNAME | Display computer name |
VER | Windows version |
WHOAMI | Current user and group info |
TASKLIST | List running processes |
TASKKILL | Terminate processes |
WMIC | WMI queries (drives, OS, memory) |
SC | Service control (query, start, stop) |
DRIVERQUERY | List installed drivers |
REG | Registry operations (query, add, delete) |
SETX | Set persistent environment variables |
| Command | Purpose |
|---|---|
PING | Test network connectivity |
IPCONFIG | IP configuration |
NSLOOKUP | DNS lookup |
NETSTAT | Network connections and ports |
TRACERT | Trace route to host |
NET USE | Map/disconnect network drives |
NET USER | Manage user accounts |
NETSH | Network configuration utility |
ARP | ARP cache management |
ROUTE | Routing table management |
CURL | HTTP requests (Windows 10+) |
SSH | Secure shell (Windows 10+) |
| Command | Purpose |
|---|---|
SCHTASKS | Create and manage scheduled tasks |
TIMEOUT | Wait N seconds (Vista+) |
START | Launch programs asynchronously |
RUNAS | Run as different user |
SHUTDOWN | Shutdown or restart |
FORFILES | Find files by date and execute commands |
| Command | Purpose |
|---|---|
WHERE | Locate executables in PATH |
DOSKEY | Create command macros |
CHOICE | Prompt for single-key input |
MODE | Configure console size and ports |
SUBST | Map folder to drive letter |
CHCP | Get or set console code page |
COLOR | Set console colors |
TITLE | Set console window title |
ASSOC / FTYPE | File type associations |
Parentheses turn compound commands into a single unit for redirection or conditional execution:
(echo Line 1 & echo Line 2) > output.txt
if exist "data.csv" (
echo Processing...
call :process "data.csv"
) else (
echo No data found.
)
The caret ^ escapes the next character:
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
* matches any sequence of characters? matches a single character (or zero at end of period-free segment)dir *.txt & REM All .txt files
ren *.jpeg *.jpg & REM Bulk rename
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
@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
@echo off and setlocal — Prevents noisy output and variable leakage to the caller.if not defined and if not exist."%~1" and "%_MY_PATH%" to handle spaces and special characters safely.exit /b instead of exit — Avoids closing the parent console window.exit /b 0 for success, non-zero for specific failures.%~dp0 for script-relative paths — Ensures the script works regardless of the caller's working directory.ROBOCOPY over XCOPY — More reliable, supports retry, mirroring, and logging.EnableDelayedExpansion when modifying variables inside loops or parenthesized blocks.echo ERROR: message 1>&2 keeps stdout clean for piping.REM for comments — :: can cause issues inside FOR loop bodies.&, |, or > can inject commands. Always quote: "%_USER_INPUT%".SETLOCAL — Prevents variable values from leaking to parent processes.DEL, RD, or ROBOCOPY to prevent unintended deletion.SET /P for sensitive input — Input is visible and stored in console history. Use a dedicated credential tool when possible.| Technique | How |
|---|---|
| Trace execution | Remove @echo off or use @echo on temporarily |
| Step through | Add PAUSE between sections |
| Check error level | echo Exit code: %ERRORLEVEL% after each command |
| Inspect variables | set _MY_ to list all variables starting with _MY_ |
| Delayed expansion issues | Variable inside ( ) block not updating? Enable !VAR! syntax |
FOR loop %% vs % | Use %%i in batch files, %i on the command line |
| Spaces in SET | set name=value not set name = value |
| Caret in pipes | After a pipe, use ^^^ to escape special chars |
| Parentheses in SET /A | Escape with ^( and ^) inside if blocks, or use quotes |
| Double percent for modulo | set /a r=14 %% 3 in batch files |
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.
| Shortcut | Action |
|---|---|
Tab | Auto-complete file/folder names |
Up / Down | Navigate command history |
F7 | Show command history popup |
F3 | Repeat last command |
Esc | Clear current line |
Ctrl+C | Cancel running command |
Alt+F7 | Clear command history |
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 |
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 |