Skip to content

How to Head and Tail a File Simultaneously in Batch Script

Learn how to display the first and last few lines of a log file at once using native Batch commands or PowerShell for efficient log analysis and troubleshooting.

When auditing massive log files, you usually care about two things: how the process started (the Head) and where it currently stands (the Tail). Displaying both at once gives you a complete context snapshot without forcing you to scroll through thousands of lines of middle content.

In this guide, we will demonstrate how to display the first and last few lines of a file simultaneously using native Batch commands.

Method 1: The "Combined View" Script

This script reads the file to count total lines, then makes a single pass to extract both the head and tail sections.

Implementation Script

@echo off
setlocal disabledelayedexpansion

set "target=SystemLog.txt"
set "linesToFetch=5"

:: Verify file exists and is not empty
if not exist "%target%" (
    echo [ERROR] File "%target%" not found.
    pause
    exit /b 1
)

:: Count total lines in the file
for /f %%C in ('find /c /v "" ^< "%target%"') do set "total=%%C"

if %total% equ 0 (
    echo [WARNING] File "%target%" is empty.
    pause
    exit /b 1
)

:: Calculate where the tail section begins
set /a "tailStart=total - linesToFetch"

:: If the file is short enough to show entirely, just display it all
if %total% leq %linesToFetch% (
    set /a "tailStart=total"
) else (
    :: If head and tail would overlap, adjust to avoid duplicating lines
    set /a "doubleCount=linesToFetch * 2"
    setlocal enabledelayedexpansion
    if !doubleCount! geq %total% (
        set /a "tailStart=linesToFetch"
    )
    endlocal
)

:: 1. Display Head
echo ==========================================
echo        HEAD: FIRST %linesToFetch% LINES
echo ==========================================

set "count=0"
for /f "usebackq delims=" %%A in ("%target%") do (
    set /a "count+=1"
    set "line=%%A"
    setlocal enabledelayedexpansion
    if !count! leq %linesToFetch% (
        echo [L:!count!] !line!
    )
    endlocal
    set /a "check=count"
    setlocal enabledelayedexpansion
    if !check! geq %linesToFetch% if %tailStart% gtr %linesToFetch% (
        goto :headDone
    )
    endlocal
)
:headDone

:: 2. Display separator if middle content was skipped
setlocal enabledelayedexpansion
if %tailStart% gtr %linesToFetch% (
    echo.
    echo     [ ... %total% total lines - middle skipped ... ]
    echo.
) else if %total% leq %linesToFetch% (
    echo.
    echo     [ File contains only %total% lines - shown above ]
    echo.
    pause
    exit /b 0
)
endlocal

:: 3. Display Tail
echo ==========================================
echo         TAIL: LAST %linesToFetch% LINES
echo ==========================================

set "current=0"
for /f "usebackq delims=" %%B in ("%target%") do (
    set /a "current+=1"
    set "line=%%B"
    setlocal enabledelayedexpansion
    if !current! gtr %tailStart% (
        echo [L:!current!] !line!
    )
    endlocal
)

echo ==========================================
pause
exit /b 0

If your file is very large, the Batch loop is slow because it must read the entire file for the tail section. PowerShell's -Tail parameter reads from the end of the file without scanning all preceding lines.

Implementation Script

@echo off
setlocal

set "target=SystemLog.txt"
set "num=5"

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

:: Get total line count for context
for /f %%C in ('find /c /v "" ^< "%target%"') do set "total=%%C"

if %total% equ 0 (
    echo [WARNING] File "%target%" is empty.
    pause
    exit /b 1
)

echo ==========================================
echo        HEAD: FIRST %num% LINES
echo ==========================================
powershell -NoProfile -Command "Get-Content '%target%' -TotalCount %num%"

echo.
echo     [ ... %total% total lines - middle skipped ... ]
echo.

echo ==========================================
echo         TAIL: LAST %num% LINES
echo ==========================================
powershell -NoProfile -Command "Get-Content '%target%' -Tail %num%"

echo ==========================================
pause
exit /b 0

Why Show Both at Once?

  1. Troubleshooting: You can verify that the configuration loaded correctly (head) and then immediately see why the script crashed hours later (tail).
  2. Visual Confirmation: In a large data migration, seeing the headers ensures the file format is correct, while seeing the tail confirms the process reached the end of the file.
  3. Dashboards: If you have an administrative dashboard, showing the start time and current status in one window provides the highest level of information density.

Best Practices

  1. Handle Empty and Short Files: Always check that the file exists and is not empty before running the head/tail logic. If the file has fewer lines than the requested count, display the entire file once rather than showing duplicate content in both sections.
  2. Prevent Overlap: If the head and tail sections would overlap (e.g., requesting 10 lines from each end of a 15-line file), detect this and adjust the tail start position so that no lines are displayed twice.
  3. Highlight the Junction: Use a visual separator like [ ... middle skipped ... ] with the total line count so the user understands they are not seeing the entire file and has a sense of its scale.
  4. Include Line Numbers: Showing that the tail starts at line 50,000 gives the user immediate context about the size of the file without needing to count.
  5. Choose the Right Method: Use Method 1 when PowerShell is unavailable or for small files. Use Method 2 for large files where the Batch loop would be unacceptably slow, especially for the tail section.

Conclusion

Displaying the head and tail of a file simultaneously is a powerful data-analysis technique that saves time and mental effort. By combining these two perspectives into a single console output, you create a high-resolution view of your logs and data sets, allowing you to bridge the gap between initial configuration and final execution results in seconds.

Navigation