Echo Outputs When Writing to File - batch-file

When I use this code to select a character from my list, it works just fine but when I write it to a file using:
echo %pwd%>>pwd.gen
It will some times put the word "ECHO" randomly in the middle of the strings generated. Here is an example:
jUrkunjcxC
ecRECHOsI5w0T
DmJfat13fT
UWXOysW7Gb
pPmS7138Ve
nFkh32ECHOJd1
You can see it appears in line 2 and 6. This only happens about 20% of the time.
Here is the code:
#echo off
title Password Generator
color f0
:firstRun
set /a cnt=0
cls
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set /p Len=What length should the password be?
set /a Len=%Len%-1
cls
set /p Amt=How many would you like to generate?
cls
goto start
:start
set alfanum=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
set pwd=
FOR /L %%b IN (0, 1, %Len%) DO (
SET /A rnd_num=!RANDOM! * 62 / 32768 + 1
for /F %%c in ('echo %%alfanum:~!rnd_num!^,1%%') do set pwd=!pwd!%%c
)
echo %pwd%>> pwd.gen
set /a cnt=%cnt%+1
if %cnt%==%Amt% goto end
goto start
:end
cls
echo Done!
echo Results have been saved to "pwd.gen"
echo.
choice /c YN /m "Restart?"
if %errorlevel%==1 goto firstRun

:start
set alfanum=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
set pwd=
FOR /L %%b IN (0, 1, %Len%) DO (
SET /A rnd_num=!RANDOM! * 62 / 32768 + 1
for /F %%c in ('echo %%alfanum:~!rnd_num!^,1%%') do set pwd=!pwd!%%c
)
alfanum is 26+26+10 = 62 characters long.
RANDOM gives a random number from 0-32,767
When RANDOM is above 32240, rnd_num gets set to 62
string indexing starts at 0 not 1
the for /F %%c command indexes alfanum:~62,1~ which is an empty string
it calls echo with no parameter, which prints ECHO is on. instead of returning a single character
for /F defaults to splitting strings with a space delimiter, which separates out the first word
%%c becomes ECHO
you add ECHO into the password.

This is a combination of a couple of things. While I'm not totally clear about the inner workings of the whole thing, I know what's causing it and how to fix it.
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 is 62 characters long. However, substrings in batch start with 0, so valid numbers go from 0 to 61. For whatever reason, an index-out-of-range combined with the ^ in 'echo %%alfanum:~!rnd_num!^,1%%' is causing the word ECHO to be displayed.
To get around this, simply don't add 1 when calculating rnd_num.
SET /A rnd_num=!RANDOM! * 62 / 32768

Related

converting back the numerical value to alphabetical letters

i found a batch .cmd project here that is able to convert the letters to its numerical value, this is it:
#echo off
:start
cls
color 9a
setlocal enableDelayedExpansion
echo.
set /p text=(your message) =
set "code=!text!"
set "chars=0abcdefghijklmnopqrstuvwxyz"
for /l %%N in (1 1 26) do for /f %%C in ("!chars:~%%N,1!") do set "code=!code:%%C=%%N !"
cls
echo.
echo (your message) = !text!
echo.
echo (numeric value) = !code!
echo.
pause
goto :start
if i type, "i love you" its numerical value will be "9 12 15 22 5 25 15 21"
what i wanted to do is to reverse the action that if i type a numerical value of something, its corresponding letter or word will appear.
how to do that?
Simply go backward for reverse
#echo off
Setlocal enableDelayedExpansion
Set "chars=0abcdefghijklmnopqrstuvwxyz"
set /p code= input code
If "!code:~-1!" neq " " set "code=!code! "
for /L %%N in (26 -1 1) do (
for /f %%C in ("!chars:~%%N, 1!") do set "code=!code:%%N =%%C!"
)
Echo text = !code!
Phil

need to read from line a to line b in a batch file

#echo off
cls
Color 0A
:Read
setlocal EnableDelayedExpansion
set file=WinSCP-5.11.2-ReadMe.txt
call :ReadInLines
call :EchoLines
echo insert other code here
pause
endlocal
(goto) 2>nul
:ReadInLines
set Counter=0
for /f "DELIMS=" %%i in ('type %file%') do (
set /a Counter+=1
title Lines In File: !Counter!
set "Line_!Counter!=%%i"
)
(goto) 2>nul
:EchoLines
For /L %%C in (1,1,%Counter%) Do (echo %%C. !Line_%%C!)
pause
So this is my code at the moment
It is able to successfully read and output the file as whole but I want to work on a way that doesn't require scrolling (for bigger files)
basically what i need to be able to do is read a certain amount of lines
example:
read lines 1 to 8 but also read lines 5 to 13
basically i need to be able to interchange the numbers it reads to, a label to call is preferred
finished code:
call.bat:
#echo off
cls
Color 0A
:: double call
call text-read-lines-alt.bat 1 8
call text-read-lines-alt.bat 9 20
pause
:: multiselect (a) (b) (a) (b) etc...
call text-read-lines-alt.bat 1 20 23 29
pause
:: call then calling outside text range (outputs first but not second)
call text-read-lines-alt.bat 1 8
call text-read-lines-alt.bat 80 100
pause
:: another call outside text range (outputs nothing)
call text-read-lines-alt.bat 90 100
pause
text-read-lines-alt.bat:
#echo off
setlocal EnableDelayedExpansion
set file=WinSCP-5.11.2-ReadMe.txt
SET "parms=%*"
call :ReadInLines
call :EchoLines
echo insert other code here
endlocal
(goto) 2>nul
:ReadInLines
set Counter=0
for /f "DELIMS=" %%i in ('type %file%') do (
set /a Counter+=1
title Lines In File: !Counter!
CALL :gate !counter!
IF DEFINED RECORD set "Line_!Counter!=%%i"
)
(goto) 2>nul
:EchoLines
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (echo %%C. !Line_%%C!)
GOTO :EOF
:gate
SET "record="
IF NOT DEFINED parms GOTO :EOF
FOR /f "tokens=1,2*" %%x IN ("%parms%") DO (
IF %1 gtr %%y SET "parms=%%z"&GOTO gate
IF %1 geq %%x SET "record=Y"
)
GOTO :EOF
and here is what all the hard work went to: http://old-school-gamer.tk/batch/text-reader/releases/
:D
#ECHO OFF
setlocal EnableDelayedExpansion
set file=WinSCP-5.11.2-ReadMe.txt
set file=100lines.txt
SET "parms=%*"
call :ReadInLines
call :EchoLines
echo insert other code here
pause
endlocal
(goto) 2>nul
:ReadInLines
set Counter=0
for /f "DELIMS=" %%i in ('type %file%') do (
set /a Counter+=1
title Lines In File: !Counter!
CALL :gate !counter!
IF DEFINED RECORD set "Line_!Counter!=%%i"
)
(goto) 2>nul
:EchoLines
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (echo %%C. !Line_%%C!)
SET /a count=0
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (
SET /a count +=1
echo !count!. !Line_%%C!
)
GOTO :EOF
:gate
SET "record="
IF NOT DEFINED parms GOTO :EOF
FOR /f "tokens=1,2*" %%x IN ("%parms%") DO (
IF %1 gtr %%y SET "parms=%%z"&GOTO gate
IF %1 geq %%x SET "record=Y"
)
GOTO :EOF
I started by recording parms=the command-tail. My 100lines.txt file is simply a file containing 100 lines "line 1".."line100"
CALLing the :gate procedure sets or clears record to specify whether the line in counter should be recorded or not. if defined works on the current status of the target variable - defined or not.
The :gate routine examines the parms string, assigning %%x to the first token, %%y to the second and %%z to the remainder of the parameters provided. If the current line number in %1 (from the calling loop) is greater then the second parameter, then assign parms to the rest of the string (which removes thefirst two parameters) and try again. parms will eventually become empty, so simply don't try processing it.
If the second parameter is not greater than the current line, see whether the current line is greater than or equal to the first parameter. If so, set record to a value so it becomes defined and hence the calling loop will record it.
So - say params is 10 13 21 28. %%x will be set to 10, %%y to 13 and %%z to 21 28. Until line 9, the line number will not be geq 10, so record remains clear. For lines 10 to 13, record will be set and the line recorded, on line 14, 14 is greater than 13, so parms becomes 21 28 and we try again.
I've modified the output procedure too. the if defined gate will only execute the echo if line_%%C is defined, so there'll be no empty lines. The downside is that the report will show the line number from the file.
The second procedure uses a fairly obvious method to serialise the output to produce the line numbers.
For example,
If the datafile contains
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
then if the parameters supplied are 3 5 meaning "lines 3 to 5 inclusive" then the output from
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (echo %%C. !Line_%%C!)
will be
Line 3
Line 4
Line 5
(note each line has its original line number.
and the output from
SET /a count=0
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (
SET /a count +=1
echo !count!. !Line_%%C!
)
will be
Line 3
Line 4
Line 5
(simply the same data but with the line numbers modified)
if you leave both of these output mechanisms in place, the output will be
Line 3
Line 4
Line 5
Line 3
Line 4
Line 5
that is, the first output concatenated with the second.
Hope msr.exe can help you for such file text processing.
msr -p file-paths -L begin-line -N end-line with -PAC to hide path/info/color.
But cannot read 2 ranges(read lines 1 to 8 but also read lines 5 to 13) at one time:
msr -p test.txt -L 1 -N 8 + msr -p text.txt -L 5 -N 13
See following screenshot.
msr.exe/msr.gcc* is a single exe tool about 1.5MB no dependencies for file/pipe text processing on Windows and Linux in my open project. See docs like peformance comparision with grep and findstr and built-in usage doc by running exe etc.

Arithmetic in batch file loop

I am writing a for loop in a batch file, which is to do arithmetic to a variable each iteration. The loop looks like this:
#echo off
setlocal enabledelayedexpansion
SET d=10
echo !d!
for /L %%t IN (0,1,9) DO (
SET /A d = %d% + 10
echo !d!
)
The arithmetic only is good for the first iteration. 'd' is to start at 10 and add by ten each time (10 20 30 ...) but it always stops at 20. In the output of the command prompt it will show:
10
20
20
...
20
20
How can I write this so it will add by ten for the entire loop?
You're close, but you missed using delayed expansion in one spot.
Change SET /A d = %d% + 10 to SET /A d = !d! + 10
#echo off
setlocal enabledelayedexpansion
SET d=10
echo !d!
for /L %%t IN (0,1,9) DO (
SET /A d = !d! + 10
echo !d!
)
Do as #JosefZ says if you need the academic exercise of arithmetic in a loop. If you want to get the same result with less code you can do this.
for /L %%t IN (20,10,110) DO echo %%t

Batch file decides that 4 > 39, How do I fix it?

Note: The file Default.txt contains one line with these three characters:1:X
#echo off
set r=0
:: For loop retrieves lines of text from the file Default.txt
FOR /F "tokens=1,2 delims=:" %%a IN (Default.txt) DO (
:: Each line is saved to a different variable.
set _%%a=%%b
set n=%%a
)
set ln=1
setlocal enabledelayedexpansion
:process
:: This loop processes all the lines in the text file.
set r=0
if "%n%" GTR "0" (
:len
:: This loop determines the length of each string.
if not "!_%ln%:~%r%,1!"=="" (
set /a r=%r%+1
goto len
)
:space
:: This loop adds spaces to each string so they will all be 39 characters in length.
if "%r%" LEQ "39" (
:: Note that there is a mandatory space at the end of the following line.
set _%ln%=!_%ln%!
set /a r=%r%+1
goto space
)
set /a n-=1
set /a ln+=1
goto process
) else (
endlocal
set _1=%_1%
)
echo %_1%]
pause >nul
When the script is run however, instead of adding 38 spaces, it only adds 3.
By turning echo back on, I found the exact point where it exits the :space loop.
C:\>if "1" LEQ "39" (
set _1=!_1!
set /a r=1+1
goto space
)
C:\>if "2" LEQ "39" (
set _1=!_1!
set /a r=2+1
goto space
)
C:\>if "3" LEQ "39" (
set _1=!_1!
set /a r=3+1
goto space
)
Up to this point, everything is working as it should.
Suddenly:
C:\>if "4" LEQ "39" (
set _1=!_1!
set /a r=4+1
goto space
)
For some reason, 4 is suddenly greater than 39, and it moves on to the next section instead of incrementing the variable and looping again like it should.
C:\>set /a n-=1
C:\>set /a ln+=1
C:\>goto process
And the program moves on and only 3 spaces are ever added to the variable.
I have no idea what the problem is and would be grateful for any insight.
C:\>if 4 LEQ 39 (
set _1=!_1!
set /a r=4+1
goto space
)
Remove quotations and try that should work , quotes are normally used with strings.
When comparing numerics, don't enclose them in quotation marks.
command: if "4" leq "39" echo hi
output: (empty line)
command: if 4 leq 39 echo hi
output: hi
The reason for that is that "4" is alphabetically after "39", so "4 is greater than "3. When comparing using quotation marks, the comparison is alphabetic, not numeric as you intended.
You've got a few other problems with your script. Don't put labels within parenthetical code blocks. You need to find some other place to put :len and :space outside of the if statement where they currently live. Strictly speaking, :: is also label named :, not a substitute for rem. When using :: as a comment, avoid using it within parenthetical code blocks as well. Use rem instead. Also, indent your code to make it easier to ensure you've got the same number of ( as ). Let me ask you: which is more readable?
option 1:
...
:space
:: This loop adds spaces to each string so they will all be 39 characters in length.
if "%r%" LEQ "39" (
:: Note that there is a mandatory space at the end of the following line.
set _%ln%=!_%ln%!
set /a r=%r%+1
goto space
)
set /a n-=1
set /a ln+=1
goto process
) else (
endlocal
set _1=%_1%
)
echo %_1%]
pause >nul
The else is a continuation of the if statement above it, right? Wrong! Properly indented, you'd see that it's part of an if statement much higher in the script.
option 2:
rem This loop adds spaces to each string so they will all be 39 characters in length.
if "%r%" LEQ "39" (
rem Note that there is a mandatory space at the end of the following line.
set _%ln%=!_%ln%!
set /a r=%r%+1
goto space
)
set /a n-=1
set /a ln+=1
goto process
) else (
endlocal
set _1=%_1%
)
echo %_1%]
pause >nul
I'll never understand why some people insist on left-justifying every line of code they write. It only makes things much more difficult to troubleshoot.
You know, there are more efficient ways to repeat characters. Rather than looping, you could do variable substring extraction.
set "spaces= "
set "39spaces=%spaces:~-39%"
If you want to get the length of a string, the fastest way I've found to do that is based on jeb's answer here:
:length <return_var> <string>
setlocal enabledelayedexpansion
if "%~2"=="" (set ret=0) else set ret=1
set "tmpstr=%~2"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if not "!tmpstr:~%%I,1!"=="" (
set /a ret += %%I
set "tmpstr=!tmpstr:~%%I!"
)
)
endlocal & set "%~1=%ret%"
goto :EOF
Example usage:
command: call :length len "The quick brown fox"
command: echo %len%
output: 19
Even if you're getting the length of a 2000 character line, that loop still counts the length in only 13 iterations, rather than potentially thousands.
Prudviraj's answer answers why your original code doesn't work, but for an easier way of padding a string to 39 characters, you could try:
Make39.bat
#echo off
setlocal
set "R=%1"
set "R=%R% " REM append 39 spaces
set "R=%R:~,39%" REM take first 39 characters
echo :123456789012345678901234567890123456789:
echo :%R%:
which works as follows:
S:\>make39 abc
:123456789012345678901234567890123456789:
:abc :
S:\>make39 "Quite a long string"
:123456789012345678901234567890123456789:
:Quite a long string :
Your comments seem to imply no string will initially be longer than 39 characters; you would have to get more inventive if this were possible (I would probably take the first 39 characters of the original R and see if that and R differ: if they did, the original would have been longer, so there would be no need to add padding).

Batch For loop array

Okay so here is what I have.
#echo off
setLocal EnableDelayedExpansion
:begin
set /a M=0
set /a number=0
set /p Input=You:
echo %Input% >> UIS
for /F "tokens=1 delims= " %%i in ("%Input%") do (
set /a M+=1
set i!M!=%%i
)
del UIS 1>nul 2>nul
:loop
set /a number+=1
set invar=!i%number%!
echo %invar%
pause > nul
goto loop
Say, for example, the Input string was "Lol this is my input string"
I want the for loop to set i!M! where M = 1 to "Lol", where M = 2 i!M! is "this" and where M = 3 i!M! is "is" and so on. Now, of course, this can't go on forever, so even if I have to stop when M = 25 or something, and say the string was only 23 words long. Then when M = 24 and 25 then i!M! is simply null or undefined.
Any help is appreciated, thank you.
for /f reads line by line, not word by word.
Here's an answer proposed at How to split a string in a Windows batch file? and modified for your situation:
#echo off
setlocal ENABLEDELAYEDEXPANSION
REM Set a string with an arbitrary number of substrings separated by semi colons
set teststring=Lol this is my input string
set M=0
REM Do something with each substring
:stringLOOP
REM Stop when the string is empty
if "!teststring!" EQU "" goto displayloop
for /f "delims= " %%a in ("!teststring!") do set substring=%%a
set /a M+=1
set i!M!=!substring!
REM Now strip off the leading substring
:striploop
set stripchar=!teststring:~0,1!
set teststring=!teststring:~1!
if "!teststring!" EQU "" goto stringloop
if "!stripchar!" NEQ " " goto striploop
goto stringloop
:displayloop
set /a number+=1
set invar=!i%number%!
echo %invar%
pause > nul
goto displayloop
endlocal
for /F command divide a line in a definite number of tokens that must be processed at once via different replaceable parameters (%%i, %%j, etc). Plain for command divide a line in an undefined number of words (separated by space, comma, semicolon or equal-sign) that are processed one by one in an iterative loop. This way, you just need to change this for:
for /F "tokens=1 delims= " %%i in ("%Input%") do (
by this one:
for %%i in (%Input%) do (
PS - I suggest you to write the array in the standard form, enclosing the subscript in square brackets; it is clearer this way:
set i[!M!]=%%i
or
set invar=!i[%number%]!

Resources