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

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.

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 /?

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.

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

Related

Writing to a file in batch

I've set up an app for a couple of friends and me in batch with a auto-updating system, but I need to add a line of code in the auto-updating system. I decided to completely rewrite the file, it takes a long time to add 'echo' in from to every line and, '>>text.txt' at the end of every line and added '^' when needed, so I was wondering if there was an easier way of writing lot's of code to a file in batch.
Example:
#echo off
rem I need a way to do the following without adding 'echo' and '>>text.txt'
echo echo Checking for updates... >text.txt
echo echo 1.4 ^>^>new.txt >>text.txt
echo ping localhost -n 2 ^>nul >>text.txt
rem and so on and so on.
Or if there is a way to simply add a new line of code in a specific place in the file, that would also help!
Thanks in advance!
The following is how you can more easily and efficiently do what your current code does, by removing all of those individual write processes.
#( Echo #Echo Checking for updates...
Echo #(Echo 1.4^)^>^>"new.txt"
Echo #(%__AppDir__%ping.exe LocalHost -n 2^)^>NUL
)>"text.txt"
There are other possibilities, but at this time, based on the lack of information in your question, I'm reluctant to expand further at this time.
If I understand correctly, then you could do the following:
in the batch file, prepend each line of text that you want to output with :::: (this constitutes an invalid label that is going to be ignored);
then use the following code:
rem // Redirect to file:
> "text.txt" (
rem // Find all lines that begin with `::::` and loop over them:
for /F "delims=" %%T in ('findstr "^::::" "%~f0"') do (
rem // Store currently iterated line:
set "TEXT=%%T"
rem // Toggle delayed expansion to avoid loss of `!`:
setlocal EnableDelayedExpansion
rem // Remove `::::` prefix and output remaining line:
echo(!TEXT:*::::=!
endlocal
)
)
replace set "TEXT=%%T" by call set "TEXT=%%T" if you want to enable percent expansion within the returned text (so it could, for example, contain %~nx0, which would then be expanded to the file name of the script).
I am using this technique a lot (without the output redirection) for help systems in my batch files (/?).
Your asked
I need a way to do the following without adding echo and >>text.txt
The script takes advantage of the line continuation character, the caret ^.
The first character after the caret ^ is always escaped, so do linefeed characters:
#echo off
SETLOCAL EnableDelayedExpansion
call :init
>text.txt (
echo #echo off%NL%
Checking for updates...%NL%
>^>new.txt echo 1.4%NL%
>NUL ping localhost -n 2
)
ENDLOCAL
exit /b
:init
( set LF=^
%= 0X0D FORM FEED =%
)
::0X0A Carriage Return
FOR /F %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
::Create newline/line continuation character
set ^"NL=^^^%LF%%LF%^%LF%%LF%^^" %= Unix-Style Endings \n =%
::set ^"NL=%CR%^^^%LF%%LF%^%LF%%LF%^^" %= Windows-Style Endings \r\n =%
exit /b
The variable %LF% is a escaped linefeed, and %NL% is a escaped %LF% plus a escaped caret ^ for line continuation.
The code
>^>new.txt echo 1.4%NL%
>NUL ping localhost -n 2
might seem strange. Why isn't the first caret ^ escaped?
Because %NL% already escaped it.
Sources:
Explain how Windows batch newline variable hack works
https://stackoverflow.com/a/5642300/12861751
https://www.dostips.com/forum/viewtopic.php?t=6369

Get directory name from array in Batch [duplicate]

This question already has answers here:
Arrays, linked lists and other data structures in cmd.exe (batch) script
(11 answers)
Closed 3 years ago.
I have a list of paths from which I want to extract folder name
I wrote:
#echo off
set paths[0]="C:\p\test1"
set paths[1]="C:\p\test2"
set paths[2]="C:\p\test3"
(for %%p in (%paths%) do (
for %%F in (%%p) do echo Processing %%~nxF
))
but seems that nothing is shown.
I expected to see:
Processing test1
Processing test2
Processing test3
It makes a big difference if first " is specified on a set command line left to variable name or left to variable value. In most cases it is better to specify it left to the variable name, especially if a variable value holding a path should be concatenated later with a file name to a full qualified file name.
See also: Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The solution for this task is:
#echo off
set "paths[0]=C:\p\test1"
set "paths[1]=C:\p\test2"
set "paths[2]=C:\p\test3"
for /F "tokens=1* delims==" %%I in ('set paths[ 2^>nul') do echo Processing %%~nxJ
The command FOR with option /F and a set enclosed in ' results in starting one more command process running in background with %ComSpec% /c and the command line specified between the two ' appended as further arguments. So executed is in this case with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c set paths[ 2>nul
The command SET outputs all environment variables of which name starts with paths[ line by line using the format VariableName=VariableValue to handle STDOUT of started background command process.
It could be that there is no environment variable of which name starts with paths[ which would result in an error message output to handle STDERR by command SET which would be redirected from background command process to handle STDERR of the command process which is processing the batch file and for that reason would be displayed in console window. For that reason a possible error message is redirected by the background command process to device NUL to suppress it with using 2>nul.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded set command line with using a separate command process started in background.
FOR captures in this case everything written to handle STDOUT of started background command process and process this output line by line after started cmd.exe terminated itself.
Empty lines are ignored by FOR which does not matter here as there are no empty lines to process.
FOR would split up a non-empty line into substrings using normal space and horizontal tab as string delimiters and would assign just first space/tab separated string to specified loop variable, if it does not start with default end of line character ;. This default line splitting behavior is not wanted here. For that reason the option delims== defines the equal sign as string delimiter.
The option tokens=1* instructs FOR to assign in this case the variable name to specified loop variable I and assign everything after the equal sign(s) after variable name without any further string splitting on equal signs to next loop variable according to ASCII table which is in this case J. That is the reason why loop variables are interpreted case-sensitive while environment variables are handled case-insensitive by the Windows command processor.
In this case only the variable value is of interest in the body of the FOR loop. For that reason just loop variable J is used on ECHO command line while I is not used at all.
The modifier %~nxJ results in removing surrounding double quotes from string value assigned to loop variable J and next get the string after last backslash or beginning of string in case of the string value does not contain a backslash at all. This is the name of the last folder in folder path string.
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 /?
for /?
set /?
UPDATE:
There is a big advantage of this solution in comparison to the other two solutions posted up to now here:
There is not used delayed environment variable expansion which is always problematic on working with file or folder names on not being 100% sure that no folder and no file contains ever an exclamation mark in its name.
Let us compare the three solutions with unusual folder names containing !.
#echo off
rem Make sure there is no environment variable defined of which name starts with
rem paths[ as suggested by Compo which is a very valuable addition on my code.
for /F "delims==" %%I in ('set paths[ 2^>nul') do set "%%I="
set "paths[0]=C:\p\test1!"
set "paths[1]=C:\p\!test2"
set "paths[2]=C:\p\!test!3"
echo/
echo Results of solution 1:
echo/
for /F "tokens=1* delims==" %%I in ('set paths[ 2^>nul') do echo Processing %%~nxJ
echo/
echo Results of solution 2:
echo/
SetLocal EnableDelayedExpansion
for /L %%i in (0,1,2) do (
for %%j in (!paths[%%i]!) do echo Processing %%~nxj
)
endLocal
echo/
echo Results of solution 3:
echo/
Setlocal EnableDelayedExpansion
Call :process paths "!paths[0]!" "!paths[1]!" "!paths[2]!"
Endlocal
echo/
pause
goto :EOF
:process
Set P_C=0
Set /a P_C-=1
For %%a in (%*) DO (
CALL :populate %1 "%%~a"
)
Set /a P_C-=1
For /L %%b in (0,1,!P_C!) DO (
ECHO Processing %1[%%b] = "!%1[%%b]!"
)
GOTO :EOF
:populate
Set "%1[!P_C!]=%~2"
Set /a P_C+=1
GOTO :EOF
The output on running this batch file is:
Results of solution 1:
Processing test1!
Processing !test2
Processing !test!3
Results of solution 2:
Processing test1
Processing test2
Processing 3
Results of solution 3:
Processing paths[0] = "C:\p\test1\p\\p\3"
Solution 1 as posted here works for all three folder names correct.
Solution 2 omits for first and second folder name the exclamation mark which will most likely cause errors on further processing. The third folder name is modified to something completely different. Enabled delayed expansion results in parsing a second time echo Processing %%~nxj after %~nxj being replaced by !test!3 with interpreting test in folder name now as environment variable name of which value is referenced delayed. There was no environment variable test defined on running this batch file and so !test!3 became just 3 before echo was executed by Windows command processor.
Solution 3 produces garbage on any folder name contains an exclamation mark, even on full qualified folder name defined before enabling delayed expansion and referenced with delayed expansion on calling the subroutine process.
Well, folder and file names with an exclamation mark in name are fortunately rare which makes the usage of delayed expansion usually no problem. But I want to mention here nevertheless the potential problems which could occur on any folder name containing one or more !.
Something like that should work :
#echo off
set paths[0]="C:\p\test1"
set paths[1]="C:\p\test2"
set paths[2]="C:\p\test3"
SetLocal EnableDelayedExpansion
for /L %%i in (0,1,2) do (
for %%j in (!paths[%%i]!) do echo Processing %%~nxj
)
pause
Define the Array within the function.
This approach can be used to define multiplay Arrays.
#ECHO OFF
Setlocal EnableDelayedExpansion
:: REM P_C is used to define the range of the Array. The -1 operations on P_C is to shift the paths parameter out of the Arrays working Index.
::REM the first parameter passed is used as the Arrays Name. all other parameters are assigned to index values 0 +
Call :process paths "C:\p\test1" "C:\p\test2" "C:\p\test3"
pause
:process
Set P_C=0
Set /a P_C-=1
For %%a in (%*) DO (
CALL :populate %1 "%%~a"
)
Set /a P_C-=1
For /L %%b in (0,1,!P_C!) DO (
ECHO Processing %1[%%b] = "!%1[%%b]!"
)
GOTO :EOF
:populate
Set "%1[!P_C!]=%~2"
Set /a P_C+=1
GOTO :EOF

How to get just the first line of a text file written into a new text file using a batch file?

Okay I have several lines in a text file. I want to get the first line and save it in another file. For example this is the text file:
put returns between paragraphs
for linebreak add 2 spaces at end
for linebreak add 2 spaces at end2
for linebreak add 2 spaces at end3
I want put returns between paragraphs to be saved into another file.
I used
for /f "tokens=" %%A in ('findstr /r "^[0-9][0-9]*$" <"C:\Users\Sherlock\Desktop\AbcImport\123.txt"') do echo 123>>1234.txt
pause
But it doesn't work at all.
How to get just the first line of a text file written into a new text file using a batch file?
Option 1 - SET /P : This is the simplest and fastest pure batch solution, provided the line does not exceed 1021 bytes, and it does not end with control characters that must be preserved. The size of the file does not matter - it will always read and write the first line very quickly.
#echo off
setlocal enableDelayedExpansion
set "ln="
<"input.txt" set /p "ln="
>"output.txt" (echo(!ln!)
Option 2 - FOR /F : This will work with lines up to ~8191 bytes long, but it can be slow if the file is really large because the FOR /F loop must read the entire file before it processes the first line. This solution is basically the same as the Mofi answer, except it disables the EOL option, so it never ignores the first line, regardless what the first character is. It does have a limitation that it will skip empty lines, so technically it does not give the correct result if the first line is empty:
#echo off
for /f usebackq^ delims^=^ eol^= %%A in ("input.txt") do echo(%%A>"output.txt"&goto :break
:break
There is a way to preserve the first line if it is empty using pure batch, but I would not bother. I would move on to ...
Option 3 - JREPL.BAT, or some other non-batch solution : Batch is quite poor at manipulating text files. You are much better off using some other scripting language like VBScript, JScript, or Powershell. Or a Windows port of any number of unix utilities.
I would use JREPL.BAT - a hybrid JScrpit/batch regular expression text processing utility that runs natively on any Windows machine from XP onward. It is way overkill for such a simple task, but it is an extremely handy, powerful, and efficient tool to have in your arsenal. Once you have it, then it can be used for many text processing tasks. Full documentation is embedded within the script.
jrepl "^.*" "$&" /jendln "quit=true" /f "input.txt" /o "output.txt"
Use CALL JREPL if you put the command within a batch script.
Here is the batch code to write just first non blank/empty line of a text file into another text file.
#echo off
for /F "usebackq delims=" %%I in ("InputTextFile.txt") do (
echo %%I>"OutputTextFile.txt"
goto ContinueAfterLoop
)
:ContinueAfterLoop
InputTextFile.txt is the file in current directory containing the first line to copy.
OutputTextFile.txt is the file created in current directory with first line from input file copied into this output file.
The command GOTO is used to exit the loop after first line is processed and continue the batch file below the loop.
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 /?
for /?
goto /?
Read also the Microsoft article about Using Command Redirection Operators.
You can use use this command:
SetLocal EnableDelayedExpansion
for /f "tokens=* delims=;" %%m in ("C:\Users\Sherlock\Desktop\AbcImport\123.txt") do (
set /p FirstLine=<%%m
echo !FirstLine!>>1234.txt
)
and for multiple file:
SetLocal EnableDelayedExpansion
for %%a in ("*") do (
for /f "tokens=* delims=;" %%m in ("%%a") do (
set /p FirstLine=<%%m
echo !FirstLine!>>1234.txt
)
)
rem Get the first line of a text file:
set /P "line=" < "C:\Users\Sherlock\Desktop\AbcImport\123.txt"
rem Write it into a new text file:
echo %line%> 1234.txt

Batch file log function for printing command output to both log file and screen

I found there are some topics similar to this problem but not exactly what I want, so I raise this topic.
I want to create a log function for printing message to both formatted log file and console output. The function is as below:
:LOGDEBUG
#echo DEBUG: %~1
if NOT EXIST %LOG_FILE% exit /b 1
#echo [%date - %time%] DEBUG: %~1 >> %LOG_FILE% 2>&1
exit /b 0
And I try to use it for printing the command execution output and if the output contains special character like "<" and ">", this function doesn't work well and prompt "The system cannot find the file specified". My code for executing a command is below:
for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
CALL :LOGDEBUG "%%a"
)
However, when I use "echo" command directly instead of the log function, the output can be printed correctly on the console. Like the following code:
for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
echo %%a
)
May I know what is the problem, and how can I print the output correctly by using the log function? Thanks
You have answered your question by own: when I use "echo" command directly...
#ECHO OFF
SETLOCAL EnableExtensions
set "LOG_FILE=D:\tempx\program.log" my testing value
rem type NUL>"%LOG_FILE%"
for /f "usebackq delims=" %%a in (`dir d:\temp 2^>NUL`) do (
CALL :LOGDEBUG "%%a"
)
rem type "%LOG_FILE%"
ENDLOCAL
exit /b
:LOGDEBUG
FOR %%A in ("%~1") do (
#echo DEBUG: %%~A
if NOT EXIST "%LOG_FILE%" exit /b 1
#echo [%date% - %time%] DEBUG: %%~A >> "%LOG_FILE%" 2>&1
)
exit /b 0
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~A etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
Here is the batch code which should work.
#echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do call :LOGDEBUG "%%a"
endlocal
goto :EOF
:LOGDEBUG
set "StringToOutput=%~1"
echo DEBUG: !StringToOutput!
echo [%DATE% - %TIME%] DEBUG: !StringToOutput!>>"%LOG_FILE%"
goto :EOF
First delayed environment variable expansion is enabled and a copy of existing environment table is made. It is explained below why this is done.
Next the name of the log file with full path is assigned to an environment variable in local variable table. This path can be with or without 1 or more spaces in path. The log file is deleted in case of existing already from a previous run. This code can be removed if you want to append new lines to already existing file. But you should add in this case code to avoid that the log file permanently increases until no free storage space anymore.
The FOR command executes the command DIR and processes each line of the output of DIR written to stdout. Blank lines are skipped. The default delimiters are space, tab and newline characters. As wanted here are the entire lines of DIR, the default delimiter list is replaced by nothing which means only newline characters remain and loop variable %a gets assigned always an entire non blank line.
The output of command DIR contains < and > which are interpreted as redirection operators if found by command processor within a line not quoted. Therefore the line for DIR output is passed quoted to subroutine LOGDEBUG. Which characters must be usually quoted are listed on last help page printed into a command prompt window when executing cmd /? in a command prompt window.
When the loop has finished, the local environment table is deleted which means LOG_FILE and StringToOutput are also removed, and previous environment is restored which usually means the delayed expansion is turned off again before batch execution exits with a jump to predefined label to end of file.
The subroutine LOGDEBUG first assigns the passed string to an environment variable without surrounding quotes just needed because of special characters in line like < and >.
Next the line is written to console window without quotes using delayed expansion as otherwise < and > would be interpreted as redirecting operators and not literally.
The same line is written also to the log file with the difference of date and time inserted at beginning of line. You missed the percent sign after date in your code. Again delayed expansion is used to get the line with the characters < and > written to file without being interpreted as redirection operators.
Important is also that there is no space before >> as otherwise each line in log file would have a trailing space. 2>&1 is useless here as command echo does not write something to stderr.
The subroutine is exited with a jump to end of file resulting in command FOR processes next 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.
call /?
del /?
dir /?
for /?
goto /?
set /?
It would be of course possible to do all the output directly in body of command FOR without using a subroutine.
#echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do (
echo DEBUG: %%a
echo [!DATE! - !TIME!] DEBUG: %%a>>"%LOG_FILE%"
)
endlocal
Delayed variable expansion is nevertheless required here as otherwise %DATE% and %TIME% would be expanded by command processor like %LOG_FILE% already on parsing entire block defined by ( and ) before command FOR is executed at all which would result in same date and time written for all lines to the log file.

Batch Script : How to find 2 lines from a file

There is a log file gettting generated and I have to find out whether the following lines are there are not?
Log file :
ftp>connected to server.
ftp> mget xyz*
200 Type set to A.
ftp> mget abc*
200 Set Type to A
ftp> bye
ANd i have to find whether the above log file has :
"200 Type set to A.
ftp>"
Please let me know how to search the consecutive lines and in the second line I am trying to locate only a string.
I'm not sure if there is an empty line between each line or not. The solution below assumes there is NOT an empty line between each line. In other words, the solution below will match 2 lines, and the 2nd line must have at least one character.
#echo off
setlocal disableDelayedExpansion
::Define LF variable containing a linefeed (0x0A)
set LF=^
::Above 2 blank lines are critical - do not remove
::Define CR variable containing a carriage return (0x0D)
for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
::The above variables should be accessed using delayed expansion
setlocal enableDelayedExpansion
::regex "!CR!*!LF!" will match both Unix and Windows style End-Of-Line
findstr /rc:"!CR!*!LF!200 Type set to A!CR!*!LF!." log.txt >nul && (echo found) || echo not found
If you are attempting to match 3 lines with an empty line in the middle, then the last line needs to change to
findstr /rc:"!CR!*!LF!200 Type set to A!CR!*!LF!!CR!*!LF!." log.txt >nul && (echo found) || echo not found
For more information about searching across line breaks, as well as other cool FINDSTR features (and bugs!) see What are the undocumented features and limitations of the Windows FINDSTR command?

Resources