I've got a somewhat weird case, where a for-loop is incredibly slow when I use findstr as the string for DO.
Its worth mentioning that the file (old-file.xml) that I'm processing contains about 200 000 lines.
This part is blazing fast, but can be rendered slower if I remove | find /c ":"
rem find total number of lines in xml-file
findstr /n ^^ old-file.xml | find /c ":" > "temp-count.txt"
set /p lines=< "temp-count.txt"
The code which is slow looks like this and I can't use the pipe trick above. It seems like the slow part is the for itself, as i'm not seeing any progress in the title bar until after 10 min.
setlocal DisableDelayedExpansion
rem start replacing wrong dates with correct date
for /f "usebackq Tokens=1* Delims=:" %%i in (`"findstr /n ^^ old-file.xml"`) do (
rem cache the value of each line in a variable
set read-line=%%j
set line=%%i
rem restore delayed expansion
setlocal EnableDelayedExpansion
rem write progress in title bar
title Processing line: !line!/%lines%
rem remove trailing line number
rem set read-line=!read-line:*:=!
for /f "usebackq" %%i in ("%tmpfile%") do (
rem replace all wrong dates with correct dates
set read-line=!read-line:%%i=%correctdate%!
)
rem write results to new file
echo(!read-line!>>"Updated-file.xml"
rem end local
endlocal
)
EDIT:
Further investigation showed me that using this single line that should display the current line number being looped takes about 10 minutes on my 8MB file of 200 000 lines. That's just for getting it to start displaying the lines.
for /f "usebackq Tokens=1* Delims=:" %%i in (`"findstr /n ^^ old-file.xml"`) do echo %%i
So it seems like findstr is writing screen output hidden for the user, but visible for the for-loop. How can I prevent that from happening while still getting the same results?
EDIT 2: Solution
The solution as proposed by Aacini and finally revised by me.
This is a snippet from a much bigger script. Wrong dates are retrieved in another loop. And total number of lines are also retrieved from another loop.
setlocal enabledelayedexpansion
rem this part is for snippet only, dates are generated from another loop in final script
echo 2069-04-29 > dates-tmp.txt
echo 2069-04-30 >> dates-tmp.txt
findstr /n ^^ Super-Large-File.xml > out.tmp
set tmpfile=dates-tmp.txt
set correctdate=2011-11-25
set wrong-dates=
rem hardcoded total number of lines
set lines=186442
for /F %%i in (%tmpfile%) do (
set wrong-dates=!wrong-dates! %%i
)
rem process each line in out.tmp and loop them through :ProcessLines
call :ProcessLines < out.tmp
rem when finished with above call for each line in out.tmp, goto exit
goto ProcessLinesEnd
:ProcessLines
for /L %%l in (1,1,%lines%) do (
set /P read-line=
rem write progress in title bar
title Processing line: %%l/%lines%
for %%i in (%wrong-dates%) do (
rem replace all wrong dates with correct dates
set read-line=!read-line:%%i=%correctdate%!
)
rem write results to new file
echo(!read-line:*:=!>>"out2.tmp"
)
rem end here and continue below
goto :eof
:ProcessLinesEnd
echo this should not be printed until call has ended
:exit
exit /b
Two points here:
1- The setlocal EnableDelayedExpansion command is executed with every line of the file. This means that about 200000 times the complete environment must be copied to a new local memory area. This may cause several problems.
2- I suggest you to start with the most basic part. How much time takes the findstr to execute? Run findstr /n ^^ old-file.xml alone and check this before trying to fix any other part. If this process is fast, then add a single step to it and test again until you discover the cause of the slow down. I suggest you not use pipes nor for /f over the execution of findstr, but over the file generated by a previous redirection.
EDIT A faster solution
There is another way to do this. You may pipe findstr output into a Batch subroutine, so the lines can be read with SET /P command. This method allows to process the lines entirely via delayed expansions and not via the command-line susbtitution of FOR /F, so the pair of setlocal EnableDelayedExpansion and endlocal commands are no longer necessary. However, if you still want to display the line number it is necessary to calculate it again.
Also, it is faster to load the wrong dates in a variable instead of process the %tmpfile% with every line of the big file.
setlocal EnableDelayedExpansion
rem load wrong dates from tmpfile
set wrong-dates=
for /F %%i in (%tmpfile%) do (
set wrong-dates=!wrong-dates! %%i
)
echo creating findstr output, please wait...
findstr /n ^^ old-file.xml > findstr.txt
echo :EOF>> findstr.txt
rem start replacing wrong dates with correct date
call :ProcessLines < findstr.txt
goto :eof
.
:ProcessLines
set line=0
:read-next-line
set /P read-line=
rem check if the input file ends
if !read-line! == :EOF goto :eof
rem write progress in title bar
set /A line+=1
title Processing line: %line%/%lines%
for %%i in (%wrong-dates%) do (
rem replace all wrong dates with correct dates
set read-line=!read-line:%%i=%correctdate%!
)
rem write results to new file
echo(!read-line:*:=!>>"Updated-file.xml"
rem go back for next line
goto read-next-line
SECOND EDIT An even faster modification
Previous method may be slighlty speeded up if the loop is achieved via for /L command instead of via a goto.
:ProcessLines
for /L %%l in (1,1,%lines%) do (
set /P read-line=
rem write progress in title bar
title Processing line: %%l/%lines%
for %%i in (%wrong-dates%) do (
rem replace all wrong dates with correct dates
set read-line=!read-line:%%i=%correctdate%!
)
rem write results to new file
echo(!read-line:*:=!>>"Updated-file.xml"
)
This modification also omit the :EOF comparison and the calculation of line number, so the time gain may be significative after repeated it 200000 times. If you use this method, don't forget to delete the echo :EOF>> findstr.txt line in first part.
A FOR /F expression will always executed/read/evaluated complete before the inner loop starts.
You can try it with
(
echo line1
echo line2
) > myFile.txt
FOR /F "delims=" %%a in (myFile.txt) DO (
echo %%a
del myFile.txt 2> nul >nul
)
It will display
line1
line2
In your case the complete ('"findstr /n ^^ old-file.xml"') will executed and cached before the loop can start
EDIT: Added Solution
I measured with a file ~20MB with 370.000 lines
type testFile.txt > nul
findstr /n ^^ testFile.txt > nul
for /F "delims=" %%a in (testFile.txt) do (
rem Nothing
)
for /f "usebackq delims=" %%a in (`"findstr /n ^^ testFile.txt"`) do ...
findstr /n ^^ testFile.txt > out.tmp
type_nul ~10000ms
findstr_nul ~30000ms
for_file ~ 1600ms
for_findstr cancled after 10 minutes
findstr_tmp ~ 500ms !!!
I would recommend to use a temporary file, it's extremly fast.
findstr /n ^^ myFile.txt > out.tmp
set lineNr=0
(
for /f "usebackq delims=" %%a in ("out.tmp") do (
set /a lineNr+=1
set "num_line=%%a"
setlocal EnableDelayedExpansion
set "line=!num_line:*:=!"
echo(!line!
endlocal
)
) > out2.tmp
Btw. Your for/F splitting can fail, if the original line begins with a colon
for /f "usebackq Tokens=1* Delims=:"
Sample: :ThisIsALabel
:ThisIsALabel
Findstr /n prepends a line number
17::ThisIsALabel
the delims=: will split the first token and handles all colons as only one seperator
ThisIsALabel
Related
I saw that in batch, to delete a specific line from a text file, you need to do it with findstrthat allow you to find your line and then delete it. But is there a way to do it when you don't know the line ? I got another program that fills the file and the batch must delete the first line. Does anyone know how to do it ?
I tried with something thet reads a line from an index and then use what I got with findstr, but it doesn't work:
#echo off
setlocal EnableDelayedExpansion
set count=1
for /f "tokens=*" %%a in (test.txt) do (
if !count! equ 1 (set "TIMER=%%a")
if !count! equ 1 (type test.txt | findstr /v %TIMER%)
set /a count+=1
)
echo %TIMER%
timeout %TIMER%
for /f "tokens=*" %%a in (test.txt) do (
echo %%a
)
pause
It tells me : FINDSTR : wrong command line
(the piece of code for the loop on the lines of the file and find a specific line was found on the internet)
So where is the problem ? Or maybe does someone know something like delete(x) and it deletes the line ? Just something that takes an INDEX... ^^'
(The last for loop is used to check if the line was removed btw)
Thanks by advance for any help !
To remove the first n lines from a file without converting tabs into spaces:
#echo off
>RemoveFirstLine.txt <test.txt (
FOR /L %%N in (1 1 1) do set/p"=" SKIP N lines
%__APPDIR__%findstr.exe /R "^"
)
This works as FINDSTR moves the pointer from STDIN, while FIND and MORE do not.
Your code mainly doesn't work because the lack of delayed expansion.
But there are easier ways to achieve your goal. If Compo's suggestion (more.com" +1 "test.txt" > "modifiedtest.txt") doesn't work for you (need to keep TABs or need to remove another line than the first one), the following might work for you:
#echo off
setlocal
set file=test.txt
set lineToDelete=1
(for /f "tokens=1* delims=:" %%a in ('findstr /N "^" "%file%" ^|findstr /bv "%lineToDelete%:"') do echo/%%b) > "%file%.tmp
move /y "%file.tmp%" "%file%"
I'm trying to write a very simple batch file for personal use...It's complete except for one thing I'm stumped on. Hopefully this is an easy fix (I'm effectively illiterate when it comes to code).
Basically what I'm trying to do is have the script choose a random line from a text file, do this a couple times with a couple different text files, then I wish to assign the output from each text file to a variable so that I can easily use them in various combinations...then repeat the process.
Here is what I have right now...
#ECHO OFF
:START
SETLOCAL
SETLOCAL EnableDelayedExpansion EnableExtensions
SET "list1=list1.txt"
FOR /f %%a IN ('type "%list1%"^|find /c /v ""') DO SET /a numlines=%%a
SET /A list1random=(%RANDOM% %% %NumLines%)
IF "%list1random%"=="0" (SET "list1random=") ELSE (SET "list1random=skip=%list1random%")
FOR /F "usebackq tokens=* %list1random% delims=" %%A IN (`TYPE %list1%`) DO (
>> output.txt ECHO %%A
)
:Finish
ENDLOCAL
GOTO START`
This procures the random line, and spits it to a text file. All is well, next step, take that random result and assign it to a variable...
#ECHO OFF
:START
SETLOCAL
SETLOCAL EnableDelayedExpansion EnableExtensions
SET "list1=list1.txt"
FOR /f %%a IN ('type "%list1%"^|find /c /v ""') DO SET /a numlines=%%a
SET /A list1random=(%RANDOM% %% %NumLines%)
IF "%list1random%"=="0" (SET "list1random=") ELSE (SET "list1random=skip=%list1random%")
FOR /F "usebackq tokens=* %list1random% delims=" %%A IN (`TYPE %list1%`) DO (
SET output1=%%A
)
>> output.txt ECHO %output1%
:Finish
ENDLOCAL
GOTO START
Now the output ceases to be random...instead it is always the last line of the referenced text file.
EDIT: The site suggested another question that was similar to mine. However, that person was having trouble getting the script to choose a valid line. I get a valid line every time, and a random one too (when I check it via echo), but a non-random line when proceeding on, assigning the output to a variable. I don't understand because it seems like a post-facto derandomization. I.E. the difference between the two scripts has nothing to do with procuring the random result, only what to do with that result AFTER it has it, right?
I appreciate any help in advance, this is the last step before I know everything I need to finish this, I'm excited!
Sorry, you're right...anyways, I figured out a simple workaround, probably not the quickest in terms of processing time, but whatever. Basically allow the initial part of the script to spit out the random result to a text file (as seemed to work just fine) then reference the text file as a variable.
#ECHO OFF
:START
SET "list1=list1.txt"
FOR /f %%a IN ('type "%list1%"^|find /c /v ""') DO SET /a numlines=%%a
SET /A listchoice=(%RANDOM% %% %NumLines%)
IF "%listchoice%"=="0" (SET "listchoice=") ELSE (SET "listchoice=skip=%listchoice%")
FOR /F "usebackq tokens=* %listchoice% delims=" %%A IN (`TYPE %list1%`) DO (
>> listoutput.txt ECHO %%A
)
Set /p list=<listoutput.txt
>> result.txt ECHO %list%
:Finish
DEL listoutput.txt
GOTO START
This is easy to do in PowerShell using the built-in Get-Random cmdlet.
$line = (Get-Content file.txt | where { $_ } | Get-Random)
Which makes it also easy in batch.
set filename=file.txt
for /f "tokens=*" %%a in ('powershell -ex bypass -c "gc %filename% | ? { $_ } | Get-Random"') do (
set "var=%%a"
)
The where { $_ } clause is only necessary to filter out any blank lines. You can omit it if you know your file has none.
I'm writing a batch file and I wanted to display a splash in the main screen. I wanted the batch file to pick a random line from a text file and ECHO it. The file name would be splashes.txt.
And in it would be like:
More addicting the lemons
Apples.
This is a splash
Test
The batch file would pick a random quote based on its line.
Like if the patch file picked line 2 it would ECHO "Apples."
Note that I'm using Windows 8.
Any ideas?
While I agree with others that you should attempt this on your own, this is a relatively straight-forward script which should serve as a good working example for learning:
#ECHO OFF
SETLOCAL EnableDelayedExpansion EnableExtensions
REM Source file.
REM The first line on this file should be blank as it will never be selected.
REM Additionally, this file should have no empty lines on the end.
SET TextFile=text.txt
REM Determine the number of lines.
SET NumLines=0
FOR /F "usebackq tokens=* delims=" %%A IN (`TYPE %TextFile%`) DO SET /A NumLines=!NumLines!+1
REM Pick a random line.
SET /A RandomLine=(%RANDOM% %% %NumLines) + 1
REM Prevent skipping all the lines.
IF "%RandomLine%"=="%NumLines%" SET RandomLine=1
REM Print the random line.
FOR /F "usebackq tokens=* skip=%RandomLine% delims=" %%A IN (`TYPE %TextFile%`) DO (
ECHO %%A
REM We are done. Stop the script.
GOTO Finish
)
:Finish
ENDLOCAL
So close - but not quite. SKIP will always be at least 1 (since SKIP=0 is invalid) hence the first line in the file can never be selected.
This is a file I derived from the above with a few tickles. I've also changed the filename because of the way I work. I'm using q27829742.txt containing the lines posted.
#ECHO OFF
SETLOCAL
SETLOCAL EnableDelayedExpansion EnableExtensions
REM Source file.
REM The first line on this file should be blank as it will never be selected.
REM Additionally, this file should have no empty lines on the end.
SET "TextFile=q27829742.txt"
REM Determine the number of lines.
FOR /f %%a IN ('type "%textfile%"^|find /c /v ""') DO SET /a numlines=%%a
REM Pick a random line.
SET /A RandomLine=(%RANDOM% %% %NumLines%)
REM Prevent skipping all the lines.
IF "%RandomLine%"=="0" (SET "RandomLine=") ELSE (SET "RandomLine=skip=%randomline%")
REM Print the random line.
FOR /F "usebackq tokens=* %RandomLine% delims=" %%A IN (`TYPE %TextFile%`) DO (
ECHO %%A
REM We are done. Stop the script.
GOTO Finish
)
:Finish
ENDLOCAL
The find /v /c method counts lines in the file (find files lines that don't match (/v) "" (so that means all lines) and count them (/c) - simply more efficient.
Pick-random-number : removing the + 1 produces a result 0..(numlines-1) which is the actual number of lines to skip.
Problem there is that skip=0 is invalid, so construct a string which is eother empty (for 0) or "skip=..." (otherwise) - all ready to be included in the for /f command-options.
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray spaces at the end of a line are NOT included in the value assigned. set /a can safely be used "quoteless".
If you know the number of lines to be, let's say 25.
You could have a vector holding each line, and then compute a random index and print out the corresponding line with the following example.
setlocal EnableDelayedExpansion
SET line[0]=Apples.
SET line[1]=This is a splash
SET line[2]=Test
SET line[3]=...
SET line[24]=many lines later...
SET /A index=%RANDOM% % 25
ECHO !line[index]!
A practical application of Jason Falkner's (and Magoo's) answer would be to their script and place it into a .cmd file that would reside in System32 (say randomline.cmd). This will integrate it into the command line utility, making it easily re-usable via a simple call line, avoiding you to have rewrite those lines over and over and over again in all your scripts. For example:
if you call the Magoo/Falkner script randomline.cmd and place it in System32
randomline.cmd
#ECHO OFF
SETLOCAL
SETLOCAL EnableDelayedExpansion EnableExtensions
REM Source file.
REM The first line on this file should be blank as it will never be selected.
REM Additionally, this file should have no empty lines on the end.
SET "TextFile=%1"
REM Determine the number of lines.
FOR /f %%a IN ('type "%textfile%"^|find /c /v ""') DO SET /a numlines=%%a
REM Pick a random line.
SET /A RandomLine=(%RANDOM% %% %NumLines%)
REM Prevent skipping all the lines.
IF "%RandomLine%"=="0" (SET "RandomLine=") ELSE (SET "RandomLine=skip=%randomline%")
REM Print the random line.
FOR /F "usebackq tokens=* %RandomLine% delims=" %%A IN (`TYPE %TextFile%`) DO (
ECHO %%A
REM We are done. Stop the script.
GOTO Finish
)
:Finish
ENDLOCAL
you'll be able to use it anypoint in the command prompt by entering
randomline any_old_text_file.txt
or if you want to use it in a cmd/bat script
call randomline any_old_text_file.txt
And if you want to set a value for a variable in your script from a random line in a file, you can do:
call radomline file_containing_values_on_each_line.txt>%temp%\randomlinevalue.txt
set /p any_old_variable=<%temp%\randomlinevalue.txt
del %temp%\randomlinevalue.txt
I am creating a code that strips through different MAC addresses randomly, but cannot figure out how to do this. My thought on how to approach this is to randomize or rearrange the order of the MAC address in the text file with this script, but I cannot figure out how to do this with a batch file. How this will work is that it will read "maclist.txt", then create a new temp file with the random order "maclist_temp.txt", that will be the rearranged file. Then, it will pull this randomized file in order.
I have tried Google and searching the web, but I haven't found anything too useful. I'm still actively looking, but any advice would be extremely useful.
Something as simple as extracting and deleting a random line and then adding to the bottom might work. Randomization would be better though, but I want to keep the original list. Something like:
Make a temp copy of maclist.txt called maclist_temp.txt
Take one random MAC address, remove it from maclist_temp.txt
Readd it to the bottom
That is all I want, but any suggestions are welcome.
You may try this batch file to help you to shuffle your maclist.txt. The usage of the batch code is
C:\> type list.txt | shuffle.bat > maclist_temp.txt
Here are the contents of shuffle.bat:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET TmpFile=tmp%RANDOM%%RANDOM%.tmp
TYPE NUL >%Tmpfile%
FOR /F "tokens=*" %%i IN ('MORE') DO SET Key=!RANDOM!!RANDOM!!RANDOM!000000000000& ECHO !Key:~0,15!%%i>> %TmpFile%
FOR /F "tokens=*" %%i IN ('TYPE %TmpFile% ^| SORT') DO SET Line=%%i&ECHO.!Line:~15!
::DEL %TmpFile%
ENDLOCAL
After issuing the above command, maclist_temp.txt will contain a randomized list of MAC addresses.
Hope this helps.
Here is a simpler method to randomize/randomise a file, no temp files needed. You can even reuse the same input filename.
Limitations are: blank lines and line starting with ; will be skipped, and lines starting with = will have all leading = signs stripped and ^ characters are doubled.
#echo off
setlocal
for /f "delims=" %%a in (maclist.txt) do call set "$$%%random%%=%%a"
(for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b)>newmaclist.txt
endlocal
I really like foxidrive's approach. Nevertheless I want to provide a solution with all the listed limitations eliminated (although cmd-related restrictions like file sizes < 2 GiB and line lengths < ~ 8 KiB remain).
The key is delayed expansion which needs to be toggled to not lose explamation marks. This solves all the potential problems with special characters like ^, &, %, !, (, ), <, >, | and ".
The counter index has been implemented in order not to lose a single line of the original text file, which could happen without, because random may return duplicate values; with index appended, the resulting variable names $$!random!.!index! are unique.
The findstr /N /R "^" command precedes every line of the original file with a line number followed by a colon. So no line appears empty to the for /F loop which would ignore such. The line number also implicitly solves the issue with leading semicolons, the default eol character of for /F.
Finally, everything up to and including the first colon (remember the said prefix added by findstr) is removed from every line before being output, hence no more leading equal-to signs are dismissed.
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A "index=0"
for /f "delims=" %%a in ('findstr /N /R "^" "%~dpn0.lst"') do (
setlocal EnableDelayedExpansion
for /F %%b in ("$$!random!.!index!") do (
endlocal
set "%%b=%%a"
)
set /A "index+=1"
)
> "%~dpn0.new" (
for /f "delims=" %%a in ('set $$') do (
set "item=%%a"
setlocal EnableDelayedExpansion
echo(!item:*:=!
endlocal
)
)
endlocal
exit /B
This seems to work. Feed it a command line parameter of the file to randomize.
#echo off
setlocal EnableDelayedExpansion
rem read the number of lines in the file
rem the find prepends the line number so we catch blank lines
for /f "delims=" %%n in ('find /c /v "" %1') do set "len=%%n"
set len=!len:*: =!
rem echo %1 has %len% lines
rem Relocate as many lines as there are lines in the file
for /l %%j in (1 1 !len!) do (
rem echo starting round %%j
rem geta random number between 1 and the number of lines in the file
set /a var=!random! %% !len! + 1
rem echo relocating line !var!
rem make sure there is no temp file
if exist %1.temp del %1.temp
rem read each line of the file, write any that don't match and then write the one that does
<%1 (
for /l %%i in (1 1 !len!) do (
rem if it is the target line then save it
if %%i == !var! (
set /p found=
rem echo saving !found!
)
rem if it is the target line then write it
if not %%i == !var! (
set /p other=
rem echo writing !other!
echo !other!>> %1.temp
)
)
rem now write the target line at the end
rem echo appending !found!
echo !found!>> %1.temp
)
rem replace the original with the temp version
move %1.temp %1>nul
)
rem print the result
type %1
Place in cmd file
for /f "tokens=2 delims=/" %%m in ('cmd /e:on /v:on /c "for /f %%f in (maclist.txt) do #echo !random!/%%f" ^| sort') do echo %%m
It spawns a cmd which reads the mac list in the inner for, prefixes a random value and a slash to the mac and sorts the list. Then this list is splitted in the outter for using the slash as delimiter and printing the mac address.
I'd like to print each line of 2 separate txt files alternately using a for loop in a batch file, I tried using an AND but was given: "AND was unexpected at this time" in cmd.exe when I ran my batch. Any ideas?
FOR /F "tokens=*" %%F in (!logPath!) AND for /f "tokens=*" %%H in (%%refLogPath) DO (
REM print each line of log file and refLog file sequentially
echo %%F
echo %%H
REM set logLine=%%F
REM check 'each line' of log file against ENG-REF.log
)
There isn't a keyword like AND, normally you couldn't solve this with two FOR loops.
But there is an alternative way to read a file with set /p.
setlocal EnableDelayedExpansion
<file2.txt (
FOR /F "delims=" %%A in (file1.txt) DO (
set /p lineFromFile2=
echo file1=%%A, file2=!lineFromFile2!
)
)
I believe this is as robust as a batch solution can get.
It handles blank lines in both files
It can read up to approximately 8k bytes on each line
The number of lines in the files does not have to match
A line can begin with any character (avoiding a FOR /F EOL issue)
A line can contain ! without getting corrupted (avoiding a problem of expanding a FOR
variable while delayed expansion is enabled)
Lines can be either Unix or Windows style.
Control characters will not be stripped from end of line
But this solution will get progressively slower as it reads a large file because it must rescan the 2nd file from the beginning for every line.
#echo off
setlocal disableDelayedExpansion
set "file1=file1.txt"
set "file2=file2.txt"
for /f %%N in ('find /c /v "" ^<"%file2%"') do set file2Cnt=%%N
findstr /n "^" "%file1%" >"%file1%.tmp"
findstr /n "^" "%file2%" >"%file2%.tmp"
set "skip=0"
set "skipStr="
for /f "usebackq delims=" %%A in ("%file1%.tmp") do (
set "ln1=%%A"
call :readFile2
set /a "skip+=1"
)
if %file2Cnt% gtr %skip% (
for /f "usebackq skip=%skip% delims=" %%B in ("%file2%.tmp") do (
set "ln2=%%B"
setlocal enableDelayedExpansion
set "ln2=!ln2:*:=!"
(echo()
(echo(!ln2!)
)
)
del "%file1%.tmp" 2>nul
del "%file2%.tmp" 2>nul
exit /b
:readFile2
if %skip% gtr 0 set "skipStr=skip=%skip% "
if %file2Cnt% gtr %skip% (
for /f "usebackq %skipStr%delims=" %%B in ("%file2%.tmp") do (
set "ln2=%%B"
goto :break
)
) else set "ln2="
:break
setlocal enableDelayedExpansion
set "ln1=!ln1:*:=!"
if defined ln2 set "ln2=!ln2:*:=!"
(echo(!ln1!)
(echo(!ln2!)
exit /b
Much better to use jeb's approach if that solution's limitations are not a concern with your files. It currently has the following limitations that could be removed with fairly minor modifications:
Files must have same number of lines
Files must not have blank lines
File1 must not contain ! character
No line in File1 can start with ;
In addition it has the following limitations when reading File2 that are inherent to the SET /P limitations
Lines must be Windows style, ending in carriageReturn lineFeed
Lines cannot exceed 1021 characters (bytes) excluding the line terminators
Control characters will be stripped off the end of each line
An even better solution would be to use something other than batch. There are many possibilities: VBS, JScript, PowerShell, perl ... the list goes on and on.