Skip to main content

How to Insert a Line at a Specific Line Number in a File in Batch Script

Injecting a new piece of data into an existing file, for example, adding a new DNS entry to a hosts file or inserting a configuration setting into the middle of an .ini file, is a complex task in Batch. Unlike a text editor, Batch cannot "open and edit" a specific line. Instead, we must read the original file line-by-line and rewrite it to a new file, inserting our new content when we reach the target line number.

In this guide, we will demonstrate how to perform this line injection using a for /f loop and a counter.

The Strategy: The Rewrite-and-Insert

To insert text at line 5:

  1. Initialize a counter to 0.
  2. Read the file line-by-line.
  3. For each line, increment the counter.
  4. If the counter equals 5, write the new text first, then the current line from the file.
  5. Otherwise, just write the current line from the file.

Implementation Script

This script inserts the line ## INSERTED HEADER ## at position 3 of a file.

@echo off
setlocal DisableDelayedExpansion

set "SourceFile=input.txt"
set "TempFile=%TEMP%\insert_temp_%RANDOM%.tmp"
set "InsertLine=3"
set "NewText=## INSERTED HEADER ##"

:: Verify source file exists
if not exist "%SourceFile%" (
echo [ERROR] Source file "%SourceFile%" not found.
pause
exit /b 1
)

:: Validate that InsertLine is a positive integer
echo(%InsertLine%| findstr /r "^[1-9][0-9]*$" >nul || (
echo [ERROR] Line number must be 1 or greater.
pause
exit /b 1
)

echo Inserting line at position %InsertLine% in "%SourceFile%"...

set "current=0"
set "inserted=0"

> "%TempFile%" (
for /f "usebackq tokens=1* delims=:" %%N in (`findstr /n "^" "%SourceFile%"`) do (
set "current=%%N"

:: Insert BEFORE line %InsertLine%
if %%N==%InsertLine% (
<nul set /p "=%NewText%"
echo(
set "inserted=1"
)

:: Write original line, including blank lines
<nul set /p "=%%O"
echo(
)
)

:: If requested line is beyond EOF, append at end
if "%inserted%"=="0" (
echo [WARNING] Line %InsertLine% exceeds file length ^(%current% lines^).
echo Appending to end of file instead.
>> "%TempFile%" <nul set /p "=%NewText%"
>> "%TempFile%" echo(
)

:: Replace original with the new version
move /y "%TempFile%" "%SourceFile%" >nul

if errorlevel 1 (
echo [ERROR] Failed to replace original file.
pause
exit /b 1
)

echo [SUCCESS] Line inserted at position %InsertLine%.
pause
exit /b 0
warning

The for /f loop skips blank lines by design and also skips lines beginning with ; (the default eol character). If your source file contains blank lines or lines starting with ;, those lines will be silently dropped during the rewrite. The line counter will also be inaccurate because skipped lines are not counted. For files where preserving all lines is critical, use the PowerShell method (Method 2) instead.

tip

The script uses the delayed expansion toggle pattern: each line is set with delayed expansion disabled (set "line=%%A") to preserve literal ! characters in the file content. It is then output with delayed expansion enabled (echo.!line!) to safely handle &, |, >, <, and other special characters. The echo. syntax also prevents ECHO is off. messages for empty values.

For large files or files that contain blank lines and special characters, PowerShell handles insertion with full accuracy.

Implementation Script

@echo off
setlocal

set "SourceFile=data.txt"
set "InsertLine=4"
set "NewText=NEW DATA LINE"

:: Verify source file exists
if not exist "%SourceFile%" (
echo [ERROR] Source file "%SourceFile%" not found.
pause
exit /b 1
)

echo Inserting line at position %InsertLine% in "%SourceFile%"...

:: List.Insert uses a zero-based index, so subtract 1 from the line number
:: If the index exceeds the list length, the line is appended to the end
powershell -NoProfile -Command ^
"$lines = [System.Collections.ArrayList]@(Get-Content -Path '%SourceFile%'); " ^
"$idx = %InsertLine% - 1; " ^
"if ($idx -ge $lines.Count) { $lines.Add('%NewText%') | Out-Null } " ^
"else { $lines.Insert([Math]::Max(0, $idx), '%NewText%') }; " ^
"$lines | Set-Content -Path '%SourceFile%' -Encoding UTF8"

if %errorlevel% equ 0 (
echo [SUCCESS] Line inserted at position %InsertLine%.
) else (
echo [ERROR] Insertion failed.
pause
exit /b 1
)
pause
exit /b 0
info

The PowerShell method uses ArrayList.Insert() which takes a zero-based index. The script subtracts 1 from the user-facing line number to convert from the natural 1-based numbering. If the requested position exceeds the file length, the line is appended to the end rather than producing an error. This method also preserves blank lines and lines starting with ;, which the Batch for /f loop cannot do.

Why Insert by Line Number?

  1. Strict File Structures: Some legacy configuration files require metadata to be on specific lines (e.g., Line 1 is the title, Line 2 is the version).
  2. Code Patching: If you are automating a patch to another script, you may need to insert a CALL or a variable declaration at the top of the file without deleting existing code.
  3. Log Injection: Inserting a timestamp or a marker line into a log file to separate different execution runs.

Best Practices

  1. Verify Source File: Always check that the input file exists before processing. A missing file will cause the for /f loop to silently produce empty output, and the move command will overwrite the missing source path with an empty temp file.
  2. Handle Out-of-Bounds: If the specified line number exceeds the total number of lines in the file, the script should handle this gracefully, either by appending to the end or by warning the user.
  3. Blank Line Awareness: The Batch for /f method drops blank lines and miscounts line positions when blank lines are present in the source file. If line-position accuracy is critical, use the PowerShell method.
  4. Special Characters in Inserted Text: If the text you are inserting contains single quotes, the PowerShell method will break because the text is wrapped in single-quote delimiters. For such content, use escaped quoting or pass the text through an environment variable.
  5. Temp File Hygiene: Use the %TEMP% directory for intermediate files and include %RANDOM% in the filename to avoid collisions when multiple instances run simultaneously.
  6. Backup Strategy: Consider creating a backup of the original file before overwriting it with the modified version. If the insertion produces unexpected results, the backup provides a recovery path.

Conclusion

Inserting a line at a specific position is a complex task for a Batch script, but it is entirely possible with a structured rewrite loop. While PowerShell offers a faster, more accurate approach that preserves blank lines and handles special characters, the native Batch method remains a valuable zero-dependency solution for lightweight configuration patching. By mastering this technique, you can programmatically update complex files while preserving their existing structure.