How to read and print contents of text file line by line?

Let us assume the text file TestFile.txt should be output line by line which is an ANSI encoded text file with just ASCII characters containing this text:

Line 1 is with nothing special. Next line 2 is an empty line.

;Line 3 with a semicolon at beginning.
   Line 4 has leading spaces.
    Line 5 has a leading horizontal tab.
Line 6 is with nothing special. Next line 7 has just a tab and four spaces if used internet browser does not remove them.
        
Line 8 is ! with exclamation marks ! in line!
? Line 9 starts with a question mark.
: Line 10 starts with a colon.
] Line 11 starts with a closing square bracket.

The batch file below outputs this text file line by line with one second delay between each line with the exception of second line which is completely empty.

@echo off
title Read line by line with delay
setlocal EnableExtensions DisableDelayedExpansion

rem Use command TIMEOUT by default for 1 second delay. But use
rem PING in case of TIMEOUT does not exist as on Windows XP.
set "DelayCommand=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
if not exist %SystemRoot%\System32\timeout.exe set "DelayCommand=%SystemRoot%\System32\ping.exe 127.0.0.1 -n 2"

for /F "usebackq eol=¿ delims=" %%I in ("TestFile.txt") do (
    echo(%%I
    %DelayCommand% >nul
)
endlocal
pause

The strange looking character ¿ after eol= is an inverted question mark with hexadecimal Unicode value 00BF used to output third line correct. A line with an inverted question mark at beginning would not be output because of this redefinition of end of line character.

This batch file code is not designed to output any type of text file with any type of character encoding independent on which characters contains the text file. The Windows command line environment is not designed for output of any text file.

It is also possible to use a different, unquoted syntax to specify the FOR options delims, eol and usebackq to define an empty list of delimiters and no end of line character:

@echo off
title Read line by line with delay
setlocal EnableExtensions DisableDelayedExpansion

rem Use command TIMEOUT by default for 1 second delay. But use
rem PING in case of TIMEOUT does not exist as on Windows XP.
set "DelayCommand=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
if not exist %SystemRoot%\System32\timeout.exe set "DelayCommand=%SystemRoot%\System32\ping.exe 127.0.0.1 -n 2"

for /F usebackq^ delims^=^ eol^= %%I in ("TestFile.txt") do (
    echo(%%I
    %DelayCommand% >nul
)
endlocal
pause

Thanks goes to aschipfl for this alternate syntax of the three FOR options with using escape character ^ to escape the equal signs and spaces in not double quoted options string to get interpreted by cmd.exe the string usebackq delims= eol= as one argument string for for /F.

There is ( instead of a space as usually used to output also correct line 7 with just a tab and some normal spaces. See also DosTips forum topic ECHO. FAILS to give text or blank line – Instead use ECHO/. echo/%%I does not correct output line 9 starting with a question mark.

It is not possible to define with an option that FOR does not ignore empty lines. But it is possible with FIND or FINDSTR to output a text file with all lines with a line number at beginning and so having no empty line anymore. The line number is enclosed in square brackets (FIND) or separated with a colon (FINDSTR) from rest of the line. It would be possible to assign to loop variable only the string after first sequence of ] or : after line number which in most cases means the entire line as in text file. But if a line in text file starts by chance with ] or :, FOR would remove this delimiter character too. The solution is this code:

@echo off
title Read line by line with delay
setlocal EnableExtensions DisableDelayedExpansion

rem Use command TIMEOUT by default for 1 second delay. But use
rem PING in case of TIMEOUT does not exist as on Windows XP.
set "DelayCommand=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
if not exist %SystemRoot%\System32\timeout.exe set "DelayCommand=%SystemRoot%\System32\ping.exe 127.0.0.1 -n 2"

for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "TestFile.txt" 2^>nul') do (
    set "Line=%%I"
    setlocal EnableDelayedExpansion
    echo(!Line:*:=!
    endlocal
    %DelayCommand% >nul
)
endlocal
pause

FINDSTR searches in the specified file with the regular expression ^ for matching lines. ^ means beginning of a line. So FINDSTR does not really search for a string in the lines of the file because of every line in a file has a beginning, even the empty lines. The result is a positive match on every line in the file and therefore every line is output by FINDSTR with the line number and a colon at beginning. For that reason no line processed later by for /F is empty anymore because of all lines start now with a line number and a colon, even the empty lines in the text file.

2^>nul is passed to cmd.exe started in background as 2>nul and results in redirecting an error message output by FINDSTR to handle STDERR to the device NUL to suppress the error message. FINDSTR outputs an error message if the file to search does not exist at all or the file cannot be opened for read because of missing NTFS permissions which allow that or because of the text file is currently opened by an application which denies the read access to this file as long as being opened by the application.

cmd.exe processing the batch file captures all lines output by FINDSTR to handle STDOUT of cmd.exe started in background and FOR processes now really all lines in the file after FINDSTR finished and the background command process closed itself.

The entire line with line number and colon output by FINDSTR executed in a separate command processes started by FOR with %ComSpec% /c and the command line within ' as additional arguments is assigned to loop variable I which is assigned next to environment variable Line.

Then delayed expansion is enabled as needed for next line which results in pushing address of current environment variables list on stack as well as current directory path, state of command extensions and state of delayed expansion before creating a copy of the current environment variables list.

Next the value of environment variable Line is output, but with substituting everything up to first colon by nothing which results in the output of the real line as stored in text file without the line number and the colon inserted at beginning by FINDSTR.

Finally the created copy of environment variables list is deleted from memory, and previous states of delayed expansion and command extension are popped from stack and set as well as the current directory path is set again as current directory and previous address of environment variables list is restored to restore the list of environment variables.

It is of course not very efficient to run for each line in text file the commands setlocal EnableDelayedExpansion and endlocal doing much more than just enabling/disabling delayed expansion, but this is necessary here to get lines with an exclamation mark correct assigned to environment variable Line and process next correct the value of Line. The efficiency loss is not really problematic here because of the delay of one second between output of each line.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • if /?
  • ping /?
  • rem /?
  • set /?
  • setlocal /?

Leave a Comment