Batch ping sweep for octet 2 and 3 - batch-file

I'm trying to write a script that will ping 10.x.x.185 for over 600 locations, and then export to a text file. I know >> can be used to append to a text file.
The IP ranges are as follows: 10.0.1.185, all the way up to 10.50.2.185, incrementing by 1 each time. I see an issue being at 10.0.255.185...
Bonus if I can have a pass and fail in two different files.
Any ideas?

The loop can be accomplished with two for /L loops, and piping output to two separate files is a little trickier, but still possible.
#echo off
:: Get the vast majority of the IP addresses
for /L %%A in (0,1,49) do (
for /L %%B in (0,1,255) do (
(ping 10.%%A.%%B.185>nul&&echo 10.%%A.%%B.185>>success.txt)||echo 10.%%A.%%B.185>>failure.txt
)
)
:: Get the 10.50.x.185 range separately since it only goes from 0 to 2
for /L %%A in (0,1,2) do (
(ping 10.50.%%A.185>nul&&echo 10.50.%%A.185>>success.txt)||echo 10.50.%%A.185>>failure.txt
)
The && means "only do this part if the prior command was successful," and the || means "only do this if the prior command failed.

The usual way in batch files to iterate over a list of consecutive numeric values is to use a for /l command. In your case, as you need two different series, you will need two nested for /l loops, one for each octet.
But as there are differences in the inner loop depending on the value of the outer loop, i will use environment variables to define how the inner loop should behave for each of the outer values.
#echo off
setlocal enableextensions enabledelayedexpansion
rem Get a carriage return into a variable to later show progress in console
for /f %%a in ('copy "%~f0" nul /z') do set "CR=%%a"
rem Define the ranges that will be used for each of the network octets
rem Values are those in for /l command: start step end
set "octetA=0 1 50"
for /l %%a in (%octetA%) do set "octetB%%a=1 1 255"
set "octetB50=1 1 2"
rem Iterate over the addresses.
rem Two streams are used to send the sucess/failure addresses to
rem the correct log file. That way we avoid having to open/write/close
rem each file for each write operation.
7>"sucess.txt" 8>"failure.txt" (
for /l %%a in (%octetA%) do for /l %%b in (!octetB%%a!) do (
rem Show current ip being tested to console
<nul set /p"=Testing 10.%%a.%%b.185!CR!"
rem Execute ping command and send the address to the
rem adecuate output stream depending on sucess/failure
( ping -n 1 10.%%a.%%b.185 2>nul | find "TTL=" >nul
) && (>&7 echo 10.%%a.%%b.185)||(>&8 echo 10.%%a.%%b.185)
)
)
echo IP address testing finished

Related

Avoid a null value in last for loop iteration?

I have a text file with one string per line (only a couple lines total). This file needs to be searched and each string stored. The script will ultimately prompt the user to choose one of the stored strings (if more than one string/line is present in the file), but the for loop is iterating an extra time when I don't want it to.
I'm using a counter to check the number of iterations, and I also read that it's probably a NL CR regex issue, but the finstr /v /r /c:"^$" in the for file-set like in this post Batch file for loop appears to be running one extra time/iteration doesn't work for me (but I probably don't understand it correctly).
The "pref" term is because the strings are to be eventually used as a prefix of files in the same folder...
#echo off
setlocal enabledelayedexpansion
set /a x=1
for /f %%a in (sys.txt) do (
set pref!x!=%%a && echo %^%pref!X!%^% && set /a x+=1
)
echo last value of x = !x!
for /L %%a in (1,1,!x!) do (
echo !pref%%a!
)
REM The rest would be to prompt user to choose one (if multiple) and
REM then use choice as a prefix with a ren %%a %prefX%%%a
If the "sys.txt" contains three lines with strings A, B, C respectively, then the output I currently get is:
pref1
pref2
pref3
last value of x = 4
A
B
C
ECHO is off.
ECHO is off. is not desired, clearly.
You just need to change your increment structure like this. (set it before each line starting from a base of 0)
#Echo Off
Setlocal EnableDelayedExpansion
Set "i=0"
For /F "UseBackQ Delims=" %%A In ("sys.txt") Do (
Set/A "i+=1"
Set "pref!i!=%%A"
Echo(pref!i!)
Echo(last value of i = %i%
For /L %%A in (1,1,%i%) Do Echo(!pref%%A!

Batch Script: Search thru multiple files for part of an IP address and log it

I have multiple TraceRT log files containing 30 hops. I'm only looking for similar IP (ex. 192.168.1) and would like to log it on one file with:
1) Successful: %IP% found in %Filename%
2) Fail: Specified IP not found in %Filename%
I'm trying to use:
rem************************************************************
:START
# ECHO OFF
rem US date
set YEAR=%DATE:~10,4%
set MONTH=%DATE:~4,2%
set DAY=%DATE:~7,2%
rem US hour
set HOUR=%TIME:~0,2%
set MIN=%TIME:~3,2%
set SEC=%TIME:~6,2%
set HUNDREDS=%TIME:~9,2%
set HOURMIN=%HOUR%%MIN%
rem Make sure that hour has two digits
IF %HOUR% GEQ 10 goto twoh
set HOUR1=%TIME:~1,1%
set TWOHOUR=0%HOUR1%
goto fulltid
:twoh
set TWOHOUR=%HOUR%
:fulltid
set FULLTIME=%TWOHOUR%'%MIN%'%SEC%'%HUNDREDS%
set FTIME=%TWOHOUR%:%MIN%:%SEC%
#echo off & setLocal EnableDELAYedeXpansion
findstr /m "192.168.1" *.txt > FILENAME
echo on
for /f "tokens=*" %%a in (*.txt ^| find "192.168.1") do (
IF %%a neq %%b (
echo Suscessful: %%a %FILENAME% >> Log%YEAR%%MONTH%%DAY%.txt
) ELSE (
echo Fail: Specified IP not found in %FILENAME% >> Log%YEAR%%MONTH%%DAY%.txt
)
)
goto START
rem************************************************************
You have specified an invalid pipe | find. You cannot pipe (a) text file(s) into a command.
Either provide the file(s) as argument(s) to find, or use redirection (this works for a single file only but not for multiple ones nor */? patterns though).
You are using for /f not correctly.
It looks as if you wanted to parse the output of find. To accomplish that, but you must enclose the command within single-quotes '. Type for /? and see the help text for more details.
The following line of code should work:
for /f "tokens=*" %%a in ('find "192.168.1" *.txt') do (
To get current date and time, I strongly recommend to read variables %DATE% and %TIME% once only and within a single line! Otherwise you might run into problems, especially concerning the fractional seconds, which might not be equal between consecutive expansions.
To ensure %HOUR% to have two digits, you simply need to use set HOUR=0%HOUR% then set HOUR=%HOUR:~-2%.
Since a one-digit %HOUR% is prefixed by a space here, you can have it even simpler (thanks for your comment, #Stephan!) by just replacing the space by a zero: set HOUR=%HOUR: =0%.

Trying to reformat a very large csv with a batch file

I have an application that exports data in the format:
1a,1b,1c1,1c2,1c3, ... (up to 1c100),1d1,1d2,1d3, ... (up to 1d100)
2a,2b,2c1,2c2,2c3, ... (up to 2c100),2d1,2d2,2d3, ... (up to 2d100)
etc.
and I am trying to reformat this into
1a,1b,1c1,1d1
1a,1b,1c2,1d2
.
.
1a,1b,1c100,1d100
2a,2b,2c1,2d1
2a,2b,2c2,2d2
etc.
I figured that if this can be done a row at a time I can just loop through the file. However I can't find a way of doing a single row with either tokens, a list, or even as a string function. There is too much data to process in a single operation (each value is about 12 chars). Tokens limit at (roughly) 64/202, a list at about 107/202 and a string at about 1000/2300
Does anyone know how this can be written into a new file?
I was trying things like:
#echo off
setlocal enableDelayedExpansion
set dimCnt=0
<example.csv (
set /p "dimList=" >nul
for %%D in (!dimList!) do (
set /a dimCnt+=1
set "dim[!dimCnt!]=%%D"
)
)
echo
for /l %%I in (3 1 102) do echo !dim[1]!,!dim[2]!,!dim[%%I]!
</code>
..besides the fact that I have missed out the last variable in the line (need to add 100 to it), I can't get more than about 80-110 values out of the list (I guess it depends on value string length)
#echo off
setlocal enableextensions enabledelayedexpansion
(for /f "tokens=1,2,* delims=," %%a in (example.csv) do (
set "data=%%c"
set "i=0"
for %%f in ("!data:,=" "!") do (
set /a "i+=1"
set "d[!i!]=%%~f"
)
set /a "end=!i!/2"
set /a "j=!end!+1"
for /l %%i in (1 1 !end!) do (
for %%j in (!j!) do echo %%a,%%b,!d[%%i]!,!d[%%j]!
set /a "j+=1"
)
)) > output.csv
endlocal
This iterates over the file, getting the first two tokens in the line (%%a and %%b), the rest of the line (%%c) is splitted and each value stored in an environment variable array (kind of). Then, the array is iterated from the start and from the middle, reading the needed values to append to %%a and %%b and generating output file.
#ECHO OFF
SETLOCAL
(
FOR /f "tokens=1,2,*delims=," %%a IN (u:\long.csv) DO (
SET rpta=%%a
SET rptb=%%b
CALL :rptcd %%c
)
)>newfile.txt
GOTO :EOF
:rptcd
SET /a lines=100
SET lined=%*
FOR /l %%x IN (1,1,99) DO CALL SET lined=%%lined:*,=%%
:loop
IF %lines%==0 GOTO :EOF
SET /a lines-=1
CALL SET lined=%lined:*,=%
FOR /f "delims=," %%x IN ("%lined%") DO ECHO %rpta%,%rptb%,%1,%%x&shift&GOTO loop
GOTO :eof
This should get you going - just need to change the input filename and output filename...
Your code does not work because SET /P cannot read more than 1023 bytes. At that point it returns the data read so far, and the next SET /P picks up where it left off. Adapting your code to compensate will be very difficult. You would be better off using FOR /F as in MC ND's answer. But beware, batch has a hard limit of 8191 characters per line in pretty much all contexts.
Better yet, you could use another scripting language like JScript, VBS, or PowerShell. Performance will be much better, and the code much more robust and far less arcane. I love working with batch, but it simply is not a good text processing language.

Concerning batch games, find and replace a string

I have made a character file in which my game pulls data and variables from. Looks like so:
playerName= Marche
playerRace= Elf
playerHP= 100
playerSPD= 200
playerATK= 120
playerDEF= 70
Final Fantasy reference anyone...? Anyway, when the character levels up, I need a batch script to find the string "playerHP= 100". playerHP is set as a variable within the script. Basically, it takes the current health, and multiplies it by 120%, increasing the number. How do I echo the result of that math to replace the current number?
For example if that didn't make any sense, I have 100 health. I level up, thus increasing my health stat by 120%, so now I have 120 health. I would want to find the string "playerHP= 100" and replace it with "playerHP= 120".
If it can be avoided I don't want to download any other commands (I've seen sed a few times). Thanks much
EDIT: Instead of searching for the string and replacing I took jeb's advice and just deleted the file and re-echoed all of the data. It ended up looking like this:
set /a LeveledUpPlayerHP=(%ppHP%* 12) / (10)
set /a LeveledUpPlayerSPD=(%ppSPD%* 12) / (10)
set /a LeveledUpPlayerATK=(%ppATK%* 12) / (10)
set /a LeveledUpPlayerDEF=(%ppDEF%* 12) / (10)
echo Updating stats...
del "C:\Users\%USERNAME%\Desktop\CMDRPG\player\playerData.dll
ping 1.1.1.1 -n 1 -w 500 > nul
echo playerName= %playerName%>playerData.dll
echo playerRace= %playerRace%>>playerData.dll
echo playerHP= %LeveledUpPlayerHP%>>playerData.dll
echo playerSPD= %LeveledUpPlayerSPD%>>playerData.dll
echo playerATK= %LeveledUpPlayerATK%>>playerData.dll
echo playerDEF= %LeveledUpPlayerDEF%>>playerData.dll
The playerName and playerRace are all loaded in prior to this section of the code. Ping is used just as a wait function to let the file delete before echoing new data. Seems to work okay. Thanks all
try this (output is in %inifile%.new):
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
SET "inifile=file"
FOR /f %%a IN ('^<"%inifile%" find /c /v ""') DO SET /a lines=%%a
< "%inifile%" (
FOR /l %%a IN (1,1,%lines%) DO (
SET "line="
SET /p "line="
IF NOT "!line:playerHP=!"=="!line!" (
FOR /f "tokens=2delims= " %%b IN ("!line!") DO SET /a HP=%%b*12/10
SET "line=playerHP= !HP!"
)
ECHO(!line!
))>"%inifile%.new"
Input/output:
>type file
playerName= Marche
playerRace= Elf
playerHP= 100
playerSPD= 200
playerATK= 120
playerDEF= 70
>test.bat
>type file.new
playerName= Marche
playerRace= Elf
playerHP= 120
playerSPD= 200
playerATK= 120
playerDEF= 70
Presumeably it does not matter what order the values appear in you file. If that is so, then the following will effectively "edit" your file.
It first uses FINDSTR to isolate the current playerHP value, and FOR /F to parse out the value from the string. SET /A increments the playerHP. Then a new file is created using FINDSTR to write all the current values except for playerHP, and then the new playerHP info is appended to the end.
#echo off
set "file=gameData.txt"
for /f "tokens=2 delims==" %%N in ('findstr /bl "playerHP=" "%file%"') do set /a "newHP=%%N*120/100"
>"%file%.mod" (
findstr /blv "playerHP=" "%file%"
echo playerHP=%newHP%
)
move /y "%file%.mod" "%file%" >nul
But why go to all that trouble. I should think you already have all your values in memory as environment variables. Simply make sure that all variables that are to be stored in a file start with a common unique prefix. In your example, they all start with "player", but you probably want something a little more generic - perhaps a symbol like #. So you could have #playerName, #playerRace, etc.
Simply update the values in memory as needed. When it comes time to save the current game state to a file, then all you need to do is
>"gameData.txt" set #
A brand new file will be created each time containing all the current values.
To load the values, you do exactly what jeb suggested:
for /f "usebackq delims=" %%A in ("gameData.txt") do set %%A
To save your data in a file, you could use a block like
(
echo playerName=%playerName%
echo playerRace=%playerRace%
echo playerHP=%playerHP%
) > player.ini
And to load it you could use
for /F "delims=" %%L in (player.ini) do set "%%L"

How to change the order of lines in a file using a batch script?

A have a text file that contains the results of a dir
dir "%local%" /b /a:d /s >> FolderList.txt
But I want to iterate in a For loop going from the last to the first line.
Since I believe this cannot be done in the For command, how can I generate a new file containing the same lines but in a inverse order?
You can't using the For command. But you can reverse the order of the dir listing that created the text file, using dir "%local%" /o-n /b /a:d /s >> FolderList.txt; the - means "reversed".
I like the general strategy of both of Aacini's original solutions, but as written they have problems (some trivial, some significant)
Original Aacini solution 1 using temp file with SORT:
Corrupts lines containing exclamation point (!)
Strips leading colon(s) (:) from each line
temp file creation using >> not as efficient as >
Uses default SORT maximum line length of 4096 bytes
Line count unnecessarily capped at 1 million
Doesn't actually provide the asked for solution (an actual file output)
Leaves behind the temporary file
Modified solution 1
Here is a version that fixes the problems. The only practical limitation is a maximum line length of 8180 bytes (characters). I'm not sure how high FINDSTR can count, but this solution will handle up to 999 billion lines. (I agree with Aacini, no one would ever want to wait for such a large file to finish using a batch solution) The line limit can easily be adjusted.
#echo off
setlocal DisableDelayedExpansion
set file="%~1"
set revfile="%~1.rev"
set tempfile="%temp%\revfile%random%.txt"
(
for /f "delims=" %%a in ('findstr /n "^" %file%') do (
set "ln=%%a"
setlocal EnableDelayedExpansion
for /f "delims=:" %%n in ("!ln!") do set "prefix=000000000000%%n"
echo !prefix:~-12!!ln:*:=!
endlocal
)
)>%tempfile%
(
for /f "delims=" %%a in ('sort /rec 8192 /r %tempfile%') do (
set "ln=%%a"
setlocal EnableDelayedExpansion
echo(!ln:~12!
endlocal
)
)>%revfile%
del %tempfile%
Aacini modified solution 1
Aacini dramatically improved the robustness and performance with a modified solution 1 using SET /P and multiple TEMP files. The SET /P solution eliminates the need for a looped SETLOCAL/ENDLOCAL toggle, but it does have a few limitations.
Lines must be terminated by <LF><CR> (normal for Windows, but Unix style is sometimes encountered in Windows world).
Lines must be <= 1024 characters
Control characters at end of line will be stripped.
Modified solution 1 take 2
If any of the above limitations are a problem, here is an adaptation of my 1st solution that uses multiple temp files. Like Aacinis modified solution, it performs linearly with file size. It is about 40% slower than Aacinis modified version.
#echo off
setlocal DisableDelayedExpansion
set file="%~1"
set revfile="%~1.rev"
set "tempfile=%temp%\revfile%random%.txt"
findstr /n "^" %file% >"%tempfile%.1"
(
for /f "usebackq delims=" %%a in ("%tempfile%.1") do (
set "ln=%%a"
setlocal EnableDelayedExpansion
for /f "delims=:" %%n in ("!ln!") do set "prefix=000000000000%%n"
echo !prefix:~-12!!ln:*:=!
endlocal
)
)>"%tempfile%.2"
sort /rec 8192 /r "%tempfile%.2" >"%tempfile%.3"
(
for /f "usebackq delims=" %%a in ("%tempfile%.3") do (
set "ln=%%a"
setlocal EnableDelayedExpansion
echo(!ln:~12!
endlocal
)
)>%revfile%
del "%tempfile%*"
Original Aacini solution 2 using environment variables:
Corrupts lines containing exclamation point (!)
Strips blank lines
Doesn't actually provide the asked for solution (an actual file output)
Modified solution 2
Here is a version that fixes the problems. The only known limitations are
A maximum line length between 8181 and 8190, depending on line number
A maximum file size slightly under 64MB.
This was my favorite solution because the file output can probably be eliminated by processing the file in the variables directly, thus completely avoiding the creation of any temporary file. Edit But based on info provided by Aacini, I learned it has severe performance problems as the environment grows. The problem is worse than Aacini realized - Even a simple SET command suffers dramatically with large environment sizes. I've posted a question regarding this phenomenon at DosTips. http://www.dostips.com/forum/viewtopic.php?f=3&t=2597 (I originally posted on SO, but apparently the question is too open ended for this site)
#echo off
setlocal disableDelayedExpansion
set file="%~1"
set revfile="%~1.rev"
set num=0
for /f "delims=" %%a in ('findstr /n "^" %file%') do (
set /a "num+=1"
set "ln=%%a"
setlocal enableDelayedExpansion
for %%n in (!num!) do for /f "delims=" %%b in (""!ln:*:^=!"") do endlocal&set "ln%%n=%%~b"'
)
setlocal enableDelayedExpansion
(
for /l %%n in (!num! -1 1) do echo(!ln%%n!
)>%revfile%
There are two relatively easy ways to sort a file in reversed order. The first one is a direct method over file contents: add line numbers to all lines, sort the file in reversed order, eliminate line numbers:
#echo off
setlocal EnableDelayedExpansion
rem Insert line numbers in all lines
for /F "tokens=1* delims=:" %%a in ('findstr /n ^^ %1') do (
set /A lineNo=1000000+%%a
echo !lineNo!:%%b>> tempfile.txt
)
rem Sort the file and show the result
for /F "tokens=1* delims=:" %%a in ('sort /r tempfile.txt') do (
echo Line %%a is %%b
)
The other method consist in load the file lines in a Batch array, that may be processed in any way you wish:
#echo off
setlocal EnableDelayedExpansion
rem Load file lines in a Batch array
set lineNo=0
for /F "delims=" %%a in (%1) do (
set /A lineNo+=1
set "line[!lineNo!]=%%a"
)
rem Process array elements in reversed order:
for /L %%i in (%lineNo%,-1,1) do (
echo Line %%i is !line[%%i]!
)
This last method works only if the size of the file is below 64 MB, because this is the limit for Batch variables.
Both methods can be modified to correctly process special characters (> < |).
HOWEVER
If you want to delete all the tree contents of a folder in bottom-up order, the "right" way to do that is via a recursive subroutine...
EDIT Answer to dbenham
As I wrote in my answer, the two methods I proposed can be modified to correctly process special characters and blank lines. In my answer I showed a general method to "change the order of lines" in reversed order paying no special attention on create an output file because the OP said in his own answer that "The objective was to reorder a list of folders to prevent problems while deleting them in sequence", so I thought that was enough to show him how to process the folders in reversed order. I also assumed that the list of folders:
Have not exclamation points (!).
Have not leading colons (:).
Folder names are shorter than 4096 bytes.
Have less than 1000000 lines.
Have not blank lines.
I even thought (and still think) that the method the OP want to use to delete a list of folders is not adequate, and I mentioned this point under a big HOWEVER in my answer proposing to use a recursive subroutine instead.
However it seems that dbenham thought that the original question was something similar to "What is the most efficient method to sort a large file in reversed order?" and criticize my methods because they lack of such features. For this reason, I should reply in terms of this new question (efficient method), right?
In first place, it's funny to me that dbenham critizice my methods because "Doesn't actually provide the asked for solution (an actual file output)", but in his own Modified solution 2 he wrote that "This is my favorite solution because the file output can probably be eliminated by processing the file in the variables directly, thus completely avoiding the creation of any temporary file". ???
The two methods proposed by dbenham have a serious problem in terms of efficiency that was already discussed in this question: the pair of setlocal EnableDelayedExpansion and endlocal commands are executed with every line of the file. If the file is large (i.e. 200 000 lines and about 8 MB, as in the previous mentioned question) the environment will be copied to a new memory area and then deleted, and this will be repeated for 200000 times! Of course, this task is time-consuming. This problem becomes worse in dbenham's Modified solution 2: as the processing of lines go on, the environment grow as it store the file contents at that point. In the last lines of the file an environment almost equal to the size of the whole file will be copied to a new memory area for every remaining line of the file. Of course, this is the worst way to achieve this process in terms of efficiency!
There is another way to process empty lines and special characters that don't require the setlocal EnableDelayedExpansion - endlocal pair. For details on this method and further discussion on efficient ways to process large files, see the previously mentioned question.
The following Batch files are my modified versions on "How to sort a large file in reversed order in an efficient way".
Modified solution 1: using temp file with SORT
#echo off
setlocal EnableDelayedExpansion
set revfile="%~1.rev"
set tempfile=%temp%\revfile%random%
rem Insert line numbers in all lines
findstr /n ^^ %1 > "%tempfile%1.txt"
find /c ":" < "%tempfile%1.txt" > "%tempfile%2.txt"
set /P lines=< "%tempfile%2.txt"
call :JustifyLineNumbers < "%tempfile%1.txt" > "%tempfile%2.txt"
del "%tempfile%1.txt"
rem Sort the file in reversed order
sort /rec 8192 /r "%tempfile%2.txt" /o "%tempfile%3.txt"
del "%tempfile%2.txt"
rem Remove line numbers
call :RemoveLineNumbers < "%tempfile%3.txt" > %revfile%
del "%tempfile%3.txt"
goto :EOF
:JustifyLineNumbers
for /L %%i in (1,1,%lines%) do (
set /A lineNo=1000000000+%%i
set /P line=
echo !lineNo!!line:*:=!
)
exit /B
:RemoveLineNumbers
for /L %%i in (1,1,%lines%) do (
set /P line=
echo !line:~10!
)
exit /B
This solution still have a limit of "only" 1147483647 lines (the maximum 32-bits signed positive integer minus the initial seed). Although this limit can be easily increased in the way suggested by dbenham, that modification imply a slower execution speed. The conclusion is: if you really want to reverse-sort a very large file don't use a Batch file, but a more efficient programming language (like C).
Modified solution 2: using a Batch variable array
#echo off
setlocal EnableDelayedExpansion
set revfile="%~1.rev"
set tempfile=%temp%\revfile%random%
rem Load file lines in a Batch array
findstr /n ^^ %1 > "%tempfile%1.txt"
find /c ":" < "%tempfile%1.txt" > "%tempfile%2.txt"
set /P lines=< "%tempfile%2.txt"
del "%tempfile%2.txt"
call :CreateArray < "%tempfile%1.txt"
del "%tempfile%1.txt"
rem Process array elements in reversed order:
(for /L %%i in (%lines%,-1,1) do echo=!ln%%i!) > %revfile%
goto :EOF
:CreateArray
for /L %%i in (1,1,%lines%) do (
set /P line=
set ln%%i=!line:*:=!
)
exit /B
EDIT A possible solution for large environment problem.
I devised an idea that may solve, at least in part, the performance problems of SET command caused by a very large environment. Let's suppose that the internal operation of SET VAR=VALUE command follow these steps:
When a new variable is defined with a value that exceed the current environment size, the environment is copied to a new area if the area beyond it is not available.
The new area is just large enough to receive the new variable. No additional space is reserved.
The important one: When a large variable is deleted, the remaining free space is NOT released. The environment memory block is never shrunk.
If previous steps are true, then the performance problems may decrease if we first reserve the desired environment space via large (8 KB) variables with the same name of the working variables. For example, to reserve 1024 KB we define 128 large variables; I suppose that the time required to define these 128 variables will be less than the time required to fill the same 1024 KB with shorter variables.
When the process is running, the definition of the first 128 working variables will take the time necessary to delete an 8 KB variable and define a shorter one, but for the variable 129 on the process must be faster because it just define a new variable in an already available space. To aid to this process, the variables must have names that place them at the end of the environment as dbenham indicated.
:ReserveEnvSpace sizeInKB
rem Define the first large variable (reserving 6 bytes for variable name)
rem (this method may be done in larger chunks until achieve the fastest one)
set z1=X
for /L %%i in (1,1,8184) do set z1=!z1!X
rem Define the rest of large variables
set /A lastVar=%1 / 8
for /L %%i in (2,1,%lastVar%) do set z%%i=!z1!
exit /B
You may use MEM /P command to check the size and placement of the environment memory block. In old MS-DOS (command.com) days the environment was placed after command.com, but if a resident program was placed after the environment, then it can't grow anymore. For this reason, the /E:nnnnn switch was provided in command.com to reserve a certain size in bytes for the environment.
I have no time to check this method for the rest of the day, but here it is for you!
The objective was to reorder a list of folders to prevent problems while deleting them in sequence.
I came up with the following algorithm. I accept suggestions to make it more efficient or better.
#ECHO off
setLocal EnableDelayedExpansion
:: File that contains a list of folders
set file_from=%~1
:: Destination file, that will contain the sorted list
if "%2"=="" (
set replace=1
set file_to=_%file_from%
) else (
set file_to=%~2
)
:: Create empty destination file
if exist "%file_to%" del "%file_to%"
copy NUL "%file_to%"
:: Temporary file
if exist ".\~Remaining.txt" del ".\~Remaining.txt"
copy "%file_from%" .\~Remaining.txt
:: Sort the order of folders
:while
set untouched=1
For /f "tokens=* delims=" %%a in (.\~Remaining.txt) Do (
:: check if line was already added
FindSTR /X /C:%%a "%file_to%"
if errorlevel 1 (
set untouched=0
:: check if folder contains sub-folders to be added
FindSTR /B /C:%%a\ .\~Remaining.txt
if errorlevel 1 (
:: remove current line from "~Remaining.txt"
FindSTR /V /B /E /C:%%a .\~Remaining.txt> .\~Remaining_new.txt
move .\~Remaining_new.txt .\~Remaining.txt
:: add current line to destination file
>> "%file_to%" ECHO %%a
goto while
)
)
)
if untouched LSS 1 (
goto while
)
if exist .\~Remaining.txt del .\~Remaining.txt
if defined replace (
ECHO REPLACE!
:: destination was not provided, so replace
if exist "%file_from%" del "%file_from%"
move "%file_to%" "%file_from%"
)
This code will reverse a text file, but with a few limitations. Blank lines are omitted and lines containing special charaters cause it to fail: & < > |
#Echo Off
If "%1"=="" Goto Syntax
If "%2"=="" Goto Syntax
If Not Exist %1 (
Echo File not found: %1
Exit /B 2
)
SetLocal EnableDelayedExpansion
Set SOF=~StartOfFile~
Set InFile=%~snx1~in
Set OutFile=%2
Set TempFile=%~snx1~temp
If Exist %OutFile% Del %OutFile%
If Exist %TempFile% Del %TempFile%
Copy %1 %InFile% >nul
:Loop
Set "Line=%SOF%"
For /F "tokens=*" %%a In (%InFile%) Do (
If Not "!Line!"=="%SOF%" Echo !Line!>>%TempFile%
Set "Line=%%a"
)
Echo %Line%>>%OutFile%
Del %InFile%
If Not Exist %TempFile% (
EndLocal
Exit /B 0
)
Rename %TempFile% %InFile%
Goto Loop
:Syntax
Echo Usage:
Echo %~n0 input-file output-file
Echo.
Exit /B 1

Resources