Skip to main content

How to Join Two Files Side-by-Side (Paste) in Batch Script

Standard file concatenation (using copy or type) adds the second file to the bottom of the first. However, sometimes you need to join them side-by-side (parallel merging). For example, if you have one file containing "Usernames" and another containing "Last Login Times," you want a single file where each line shows: Username | Last Login.

In this guide, we will demonstrate how to perform a side-by-side join (similar to the Linux paste command) using an index-based loop.

The Strategy: The Indexed Merge

Batch cannot read two files simultaneously using two different for /f loops. The most reliable way to align them is:

  1. Read File A into an array of indexed variables: ROW_1, ROW_2, etc.
  2. Read File B line-by-line, and for each line, retrieve the corresponding indexed variable from File A.
  3. Output both values together on a single line.

Implementation Script

@echo off
setlocal disabledelayedexpansion

set "FileA=fileA.txt"
set "FileB=fileB.txt"
set "Output=MasterReport.txt"
set "Separator= | "

:: Verify both source files exist
if not exist "%FileA%" (
echo [ERROR] File "%FileA%" not found.
pause
exit /b 1
)
if not exist "%FileB%" (
echo [ERROR] File "%FileB%" not found.
pause
exit /b 1
)

echo Joining "%FileA%" and "%FileB%" side-by-side...

:: 1. Read File A into an indexed array of variables
set "countA=0"
for /f "usebackq delims=" %%A in ("%FileA%") do (
set /a "countA+=1"
set "line=%%A"
setlocal enabledelayedexpansion
set "ROW_!countA!=!line!"
endlocal
)

:: 2. Read File B and combine with the corresponding array entry
set "countB=0"
(
for /f "usebackq delims=" %%B in ("%FileB%") do (
set /a "countB+=1"
set "lineB=%%B"
setlocal enabledelayedexpansion

:: Retrieve the matching line from File A using the index
call set "valA=%%ROW_!countB!%%"
echo(!valA!!Separator!!lineB!
endlocal
)
) > "%Output%"

:: 3. Check for line count mismatch
setlocal enabledelayedexpansion
if !countA! neq !countB! (
echo [WARNING] Line count mismatch: "%FileA%" has !countA! lines, "%FileB%" has !countB! lines.
echo Output contains !countB! joined lines.
)
endlocal

echo [SUCCESS] Combined file saved to "%Output%".
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 either source file contains blank lines, the row alignment between the two files will be silently corrupted, line 5 of File A might be joined with line 3 of File B if File B had two blank lines before line 3. For files with blank lines, 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" and set "lineB=%%B") to preserve literal ! characters in the file content. The call set "valA=%%ROW_!countB!%%" technique performs double expansion, the inner !countB! resolves first via delayed expansion, then the outer %%ROW_N%% resolves via call, retrieving the correct indexed variable.

For large files or files containing blank lines and special characters, PowerShell handles the parallel merge more reliably.

Implementation Script

@echo off
setlocal

set "FileA=fileA.txt"
set "FileB=fileB.txt"
set "Output=merged.txt"
set "Separator=,"

:: Verify both source files exist
if not exist "%FileA%" (
echo [ERROR] File "%FileA%" not found.
pause
exit /b 1
)
if not exist "%FileB%" (
echo [ERROR] File "%FileB%" not found.
pause
exit /b 1
)

echo Joining "%FileA%" and "%FileB%" side-by-side...

:: Read both files into arrays, iterate by index, and join
:: Math.Max ensures we iterate through the longer file,
:: padding with empty values for the shorter one
powershell -NoProfile -Command ^
"$a = @(Get-Content -Path '%FileA%'); " ^
"$b = @(Get-Content -Path '%FileB%'); " ^
"$max = [Math]::Max($a.Count, $b.Count); " ^
"$result = for ($i = 0; $i -lt $max; $i++) { " ^
" $left = if ($i -lt $a.Count) { $a[$i] } else { '' }; " ^
" $right = if ($i -lt $b.Count) { $b[$i] } else { '' }; " ^
" \"$left%Separator%$right\" " ^
"}; " ^
"$result | Set-Content -Path '%Output%' -Encoding UTF8"

if %errorlevel% equ 0 (
echo [SUCCESS] Combined file saved to "%Output%".
) else (
echo [ERROR] Join operation failed.
pause
exit /b 1
)
pause
exit /b 0
info

The PowerShell method iterates through the longer of the two files using [Math]::Max(), producing empty values for the shorter file's missing lines. This ensures no data is silently dropped when the files have different line counts. It also preserves blank lines, which the Batch for /f method cannot do.

Why Join Files Side-by-Side?

  1. Reconciling Reports: If you export a list of server names from one tool and disk usage from another, joining them side-by-side creates a unified report.
  2. Generating CSVs: You can combine raw data columns into a properly formatted .csv file by using a comma as the separator.
  3. Audit Comparison: Placing an original and modified file side-by-side (using a vertical bar |) makes it easier to visually inspect changes in small snippets.

Best Practices

  1. Verify Source Files: Always check that both input files exist before processing. A missing file will cause the for /f loop to produce empty variables, and the output will contain only data from the other file.
  2. Equal Line Counts: Always try to ensure your input files have the same number of lines. If they differ, decide in advance whether to truncate to the shorter file (Batch default) or pad with empty values for the longer file (PowerShell method).
  3. Blank Line Awareness: The Batch method drops blank lines from both files, which corrupts row alignment silently. If either file may contain blank lines, use the PowerShell method.
  4. Configurable Separator: Define the separator character as a variable (set "Separator= | ") rather than hardcoding it in the echo statement. This makes it easy to switch between pipe-delimited, comma-delimited, or tab-delimited output.
  5. Memory Limits: Loading File A into indexed variables (ROW_1, ROW_2, etc.) consumes environment space. For files with tens of thousands of lines, the environment block may run out of space. Use the PowerShell method for large files.
  6. Special Characters: Use the delayed expansion toggle pattern when reading and outputting lines. Without it, column values containing &, |, >, <, or ! will corrupt the output or break the script.

Conclusion

Joining files side-by-side is a powerful way to synthesize information from separate data sources. While it requires variable-indexing techniques in native Batch, it allows you to create structured, multi-column reports that transform raw text into actionable intelligence. By mastering the side-by-side join, you move beyond simple file stacking and into the realm of true data reconciliation.