mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-30 12:15:56 +00:00
* new skill batch-files * batch-files: codespell, re-run start, suggestions, txt assets codespellrc: add FO for tasklist option validate-readme: re-run npm start apply suggestions from code review batch-files: change asset templates to text files * codespellrc: resolve spelling in comment
555 lines
17 KiB
Markdown
555 lines
17 KiB
Markdown
---
|
||
name: batch-files
|
||
description: '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.'
|
||
---
|
||
|
||
# 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 `.bat` or `.cmd` files
|
||
- Automating Windows tasks (file operations, deployments, backups)
|
||
- Building CLI tools intended for a `bin/` 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 `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:
|
||
|
||
1. **Variable substitution** — `%VAR%` tokens are replaced with environment variable values. `%0`–`%9` reference batch arguments. `%*` expands to all arguments.
|
||
2. **Quoting and escaping** — Caret `^` escapes special characters (`& | < > ^`). Quotation marks prevent interpretation of enclosed special characters. In batch files, `%%` yields a literal `%`.
|
||
3. **Syntax parsing** — Lines are split into pipelines (`|`), compound commands (`&`, `&&`, `||`), and parenthesized groups `( )`.
|
||
4. **Redirection** — `>` overwrites, `>>` appends, `<` reads input, `2>` redirects stderr, `2>&1` merges stderr into stdout, `>NUL` discards output.
|
||
|
||
## Variables
|
||
|
||
### Environment Variables
|
||
|
||
```bat
|
||
set _MY_VAR=Hello World
|
||
echo %_MY_VAR%
|
||
set _MY_VAR=
|
||
```
|
||
|
||
- `set` with no arguments lists all variables
|
||
- `set _PREFIX` lists variables starting with `_PREFIX`
|
||
- No spaces around `=` — `set name = val` sets 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
|
||
|
||
```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
|
||
```
|
||
|
||
- `!VAR!` expands at execution time (delayed)
|
||
- `%VAR%` 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: `equ`, `neq`, `lss`, `leq`, `gtr`, `geq`. Use `/i` 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
|
||
```
|
||
|
||
`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
|
||
|
||
```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
|
||
```
|
||
|
||
- `call :label args` invokes a function
|
||
- `exit /b` returns from the function (not the script)
|
||
- Use the `endlocal & set` trick to pass values out of a scoped block
|
||
|
||
## Arithmetic
|
||
|
||
`set /a` 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 (`0xFF`) and octal (`077`) literals are supported.
|
||
|
||
## Error Handling
|
||
|
||
### Error Level Conventions
|
||
|
||
- `0` = success
|
||
- Non-zero = failure (typically `1`)
|
||
|
||
```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 |
|
||
|---------|---------|
|
||
| `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 |
|
||
|
||
### Text Search and Processing
|
||
|
||
| 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 |
|
||
|
||
### System Information
|
||
|
||
| 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 |
|
||
|
||
### Network
|
||
|
||
| 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+) |
|
||
|
||
### Scheduling and Automation
|
||
|
||
| 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 |
|
||
|
||
### Shell Utilities
|
||
|
||
| 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 |
|
||
|
||
## 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
|
||
|
||
1. **Always start with `@echo off` and `setlocal`** — Prevents noisy output and variable leakage to the caller.
|
||
2. **Validate inputs before processing** — Check required arguments and file existence early. Use `if not defined` and `if not exist`.
|
||
3. **Quote paths and variables** — Use `"%~1"` and `"%_MY_PATH%"` to handle spaces and special characters safely.
|
||
4. **Use `exit /b` instead of `exit`** — Avoids closing the parent console window.
|
||
5. **Return meaningful exit codes** — `exit /b 0` for success, non-zero for specific failures.
|
||
6. **Use `%~dp0` for script-relative paths** — Ensures the script works regardless of the caller's working directory.
|
||
7. **Prefer `ROBOCOPY` over `XCOPY`** — More reliable, supports retry, mirroring, and logging.
|
||
8. **Use `EnableDelayedExpansion` when modifying variables inside loops or parenthesized blocks.**
|
||
9. **Write errors to stderr** — `echo ERROR: message 1>&2` keeps stdout clean for piping.
|
||
10. **Use `REM` for comments** — `::` can cause issues inside `FOR` 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: `"%_USER_INPUT%"`.
|
||
- **Use `SETLOCAL`** — Prevents variable values from leaking to parent processes.
|
||
- **Sanitize file paths** — Validate paths before passing to `DEL`, `RD`, or `ROBOCOPY` to prevent unintended deletion.
|
||
- **Avoid `SET /P` 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 `@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 |
|
||
|
||
## 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 |
|
||
|----------|--------|
|
||
| `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 |
|
||
|
||
## 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 |
|