0

So, I have no clue on how to have CMD echo lines from a *.txt text file one at a time with a tiny delay to make it seem like it's processing.

Is this even possible with a batch alone?

I've tried doing research, but I can't find sufficient text manipulation to be able to do this, but I do know how to make a pause between each command and how to do loops.

Mofi
  • 46,139
  • 17
  • 80
  • 143
Jack Avante
  • 1,405
  • 1
  • 15
  • 32

3 Answers3

4

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 /?
Mofi
  • 46,139
  • 17
  • 80
  • 143
  • 1
    You should use `echo(` rather than `echo/` (imagine a line containing `?`). And I would not use (invisible) control characters like the form-feed in a batch file; you could use the unquoted syntax `for /F usebackq^ delims^=^ eol^= %%A` here instead. Anyway, why did you answer this off-topic question after all? – aschipfl Jul 29 '18 at 10:39
3

Despite your question being off topic, I have decided to include this because, there are already two answers and it can be achieved using a single line.

From a batch file:

@For /F Tokens^=1*Delims^=]^ EOL^= %%A In ('Find /N /V ""^<"C:\test.txt"') Do @Echo(%%B&>Nul PathPing 127.0.0.1 -n -q 1 -p 450

From the Command Prompt:

For /F Tokens^=1*Delims^=]^ EOL^= %A In ('Find /N /V ""^<"C:\test.txt"') Do @Echo(%B&>Nul PathPing 127.0.0.1 -n -q 1 -p 1350

Both examples do not omit empty lines from your source file, C:\test.txt, which can be changed as required.
I have used PathPing for the 'tiny delay', because it seems more controllable; to adjust the delay all you need to do is change the last number until you find your most pleasing output.

Compo
  • 36,585
  • 5
  • 27
  • 39
  • It is right that empty lines are not skipped because of using __FIND__ to output all lines with a line number in square brackets and let __FOR__ ignore everything up to end of first __sequence__ of `]`. But I want to add that on lines with one or more `]` at beginning those closing square brackets are also not output by this solution like on using `findstr /N "^" "C:\Test.txt"` and using `:` as delimiter in __FOR__ to ignore the line number followed by a colon resulting in no output of colons at beginning of a line. – Mofi Jul 29 '18 at 15:15
  • @Mofi, agreed, however the likelihood of a line beginning with `]` is far less than one being empty or one beginning with `:`! _In fact because the character should commonly close a preceding `[` it should only really only appear at the start of a line which has been output from fixed line length routine or from one using it for an image._ – Compo Jul 29 '18 at 15:53
  • I agree, there are lots of text files with `:` at beginning of a line like batch files or assembler files. Text files with a closing square bracket at beginning of a line are really VERY rare. The only text files I have ever seen in last 25 years with `]` at beginning are XML files containing a [CDATA](http://www.w3.org/TR/xml/#sec-cdata-sect) section on which embedded data ends with a line ending. So your decision to use __FIND__ is definitely a very good one as working for approximately 99.99999999% of all text files which is the reason for my upvote for your single command line solution. – Mofi Jul 29 '18 at 16:03
  • As a supplement to your above @Mofi, _and in my possibly limited knowledge of XML_, I have found that the CDATA sections tend to be closed indented, i.e. their lines begin with whitespace followed by the closing square bracket. In those cases my code should work as intended. – Compo Jul 30 '18 at 00:15
  • There are two types of XML files, those designed for being viewed/edited also by people are well-formatted with line breaks and indents, and the others created by programs for programs have very often no line breaks and no indents to reduce size and speed up read/write. `]]>` for closing a CDATA section should be in an XML file where the embedded data section really ends as here ends the section. By putting `]]>` extra on a new line indented correct means appending a line ending and spaces/tabs to data section which the data do not really have.which could be not good depending on data. – Mofi Jul 30 '18 at 05:07
  • Thanks @Mofi, so the 0.00000001% of filles which would fail with my line viewing code above are the XML files which were not designed to be viewed in a console window. – Compo Jul 30 '18 at 07:06
  • Yes, that's right which is the reason why the posted single command line for this task is really very good. – Mofi Jul 30 '18 at 07:37
1

Give a try for this batch script :

@echo off
Title Read line by line with delay
set "InputFile=TestFile.txt"
set "delay=1" Rem Delay one seconds, you can change it for your needs
setlocal enabledelayedexpansion
for /f "tokens=*" %%A in ('Type "%InputFile%"') do (
  set /a N+=1
  set "Line[!N!]=%%A"
)

for /l %%i in (1,1,%N%) do (
    echo !Line[%%i]!
    Timeout /T %delay% /nobreak>nul
)
pause
Hackoo
  • 18,337
  • 3
  • 40
  • 70