This is my first time trying scripting and I'm trying to create a small program that does a simple division and mod in a loop, and then calculates the average of the mod results.
This is what I have tried in Linux .sh, but how could I make it compatible with Windows .bat? Your help is very appreciated.
echo "enter first number:"
read first_num
echo “enter second number:”
read second_num
while [ first_num && second_num != 999 ]
do
if [ second_num != 0 ]; then
echo "Enter first number:"
read first_num
echo"Enter second number:"
read second_num
echo first_num "/" second_num "=" $((first_num / second_ num)) >> file.txt
else
echo "ERROR. Cannot divide by 0. Enter another number:"
fi
done
if [ first_num == 999 || second_num == 999 ]; then
echo "You have exited the loop."
fi
#Mod 5 of numbers 1-100:
for i in {1...100}
do
result=$((i % 5))
echo i + "%5=" + result >> file.txt
done
#Average of results:
int sum=0
for (( i=1; i<101; i=i+1 ))
do
sum=sum+$((i % 5))
average=$((sum/100))
echo average
echo average >> file.txt
done
echo "enter first number:"
read first_num
becomes
set /p first_num="Enter first number "
while [ first_num && second_num != 999 ]
don't have a WHILE - have to wire it. Think clubs and rocks.
:loop
if %first_num%==999 goto endloop
if %second_num%==999 goto endloop
...
goto loop
:endloop
:name is a label, %var% retrieves contents of var - is always a string enclose in quotes if the string includes spaces.
if [ second_num != 0 ]; then
translated is
if NOT %second_num%==0 ( ...things... ) else (...other things...)
or, of course
if %second_num%==0 ( ...other things... ) else (...things...)
Quirk: (one of many) : the first open-parenthesis MUST occur on the same physical line as the IF and the ELSE must be on the same physical line as the ) of the on-true statemet sequence.
echo first_num "/" second_num "=" $((first_num / second_ num)) >> file.txt
Can't do a calculation in an echo
set /a result=(first_num / second_ num)
OR
set /a result=(%first_num% / %second_ num%)
SET /A applies the results of an arithmetic expression - later addition and more C-like semantics
then
echo %first_num% / %second_num% = %result% >> file.txt
purely stringing the elements together.
Next there is a small problem. During the parsing process, any %var% is replaced by its PARSE-TIME value and THEN the line is executed. Consequently, the ECHO line above would show the values as they stood when the IF statement was entered, not after the calculations.
Two cures:
You can use SETLOCAL ENABLEDELATEDEXPANSION to switch the interpreter mode. In DELAYEDEXPANSION mode, !var! may be used to retrieve the RUN-TIME value of var. A SETLOCAL is terminated by an ENDLOCAL or by reaching END-OF-FILE in the same context. Any environment changes after a SETLOCAL are undone by an ENDLOCAL which is why it's often performed immediately after the #echo off - keeps the environment clean.
second cure is to use a subroutine. CALL :SUB (the colon means 'internal subroutine - start label is in this batchfile'. Omitting it means 'this is an external executable') The CALL creates a new context, copying the then-existing environment variables, so
:sub
echo %first_num% / %second_num% = %result% >> file.txt
goto :eof
will display the variables from the environment as it stood when a CALL :SUB was executed.
Note that GOTO :EOF (the colon is REQUIRED means 'go to physical end-of-file' - the label EOF should not be declared...
(beware also flow-through to subroutines normally placed at the end of batchfiles. A judicious GOTO :EOF ensures that flow-through does not occur...
#Mod 5 of numbers 1-100:
The comments indicator is officially REM
rem Mod 5 of numbers 1-100:
BUT
::Mod 5 of numbers 1-100:
is often used as it's easier to type BUT since it's actually a misuse of a label, it is actually a label, and labels can't be used in a compound statement, you you can't use it within the parentheses of IF ... (...) else (...) or FOR...DO (...)
for i in {1...100}
becomes
for /L %%i in (1,1,100) do (
The metavariable %%i IS case-sensitive and a single character. in a FOR /L the elements are (start,step,end) - see FOR /? from the prompt (or generally command /? from the prompt) for docco...
result=$((i % 5))
becomes
set /a result=%%i %% 5
/a because the RHS is an arithmetic expression to be evaluated; %% 5 because % escapes %, the space is irrelevant and the processor needs to know that the MOD operator % is being used, not %5 (the fifth command-line argument)
int sum=0
No such thing as types; all environment variables are strings and only interpreted as integers by the set /a statement
so - that's about all there is to it...
Hope you're looking for this:
#echo off
setlocal enabledelayedexpansion
> file.txt type nul
:loopInput
echo enter first number:
set /p first_num=
echo enter second number:
set /p second_num=
if !first_num! neq 0 (
if !second_num! neq 999 (
if !second_num! equ 0 (
echo ERROR. Cannot divide by 0. Enter another number:
goto loopInput
)
goto loopDiv
)
)
goto :skipDiv
:loopDiv
set /a division=first_num/second_num
>> file.txt echo !first_num! / !second_num! = !division!
goto loopInput
:skipDiv
echo You have exited the div loop.
>> file.txt echo Mod 5 of numbers 1-100:
for /l %%a in (1,1,100) do (
set /a mod=%%a%%5
>> file.txt echo %%a %% 5 = !mod!
)
set sum=0
for /l %%a in (1,1,100) do (
set /a sum+=%%a%%5
)
set /a average=sum/100
>> file.txt echo Average of results: !average!
Related
I'm trying to created a Batch program that has multiple echo commands and if commands in one line. The problem is when I type a command after an echo command, it thinks it's part of the echo string and prints it to the screen instead of executing it.
For example:
if %var1% == 1 echo %var2% (right here I need to end the echo) if %var3% == 1 echo %var4%
echo.
if %var5% == 1 echo %var6% (right here I need to end the echo) if %var7% == 1 echo %var8%
I'm sure it's fairly simple, but I need to know if there's some character or command that will end a line without being interpreted as part of the message. Thanks in advance!
You need to write a string without a linefeed. echowon't to that. Instead you can use this workaround:
<nul set /p"=first "
<nul set /p"=second "
echo third
for your example:
if %var1% == 1 <nul set /p=%var2%
if %var3% == 1 echo %var4%
You can use && to separate pieces of code:
if %Var1% equ 12 echo %Var1% && if %Var2% neq 12 echo %Var2%
I tested it, it works.
I posted this answer here because it seems that my previous comment go unnoticed.
Usually an & is used to separate several individual commands in the same line; however, if the & is placed after an if or for (in the same line), then the & groups all commands in the same if or for. If you want to put several individual if or for commands (in the same line), you need to isolate each one enclosing they in parentheses:
(if %var1% == 1 echo %var2%) & if %var3% == 1 echo %var4%
(if %var5% == 1 echo %var6%) & (if %var7% == 1 echo %var8%) & echo After two previous if's
(if %varX% == 1 echo This one & echo This also) & echo Independently of previous if
A user defined input file has to be integrated into the entries of pre-set output file,
changing the data at a given block [A-Z] and index [1-75] position.
The input file structure with wildcards for variable parts:
* 00asr[1-75] 00asr*
b -v -o 00asr34 00asr34.hkx (example)
b -v 00asr35 00asr35.hkx (example)
Output file as above but with multiple blocks [A-Z]asr[1-75]:
* Aasr[1-75] Aasr*
* Basr[1-75] Basr*
...
* Zasr[1-75] Zasr*
The user has to pick a given letter A-Z to determine parts of the string and the block to replace information in.
Then we can replace the %input% substrings 00asr with %block%asr; they will then match given substrings in the %output%:
* 00asr[1-75] 00asr* >> * Zasr[1-75] Zasr* in the case of Z.
#ECHO OFF
ECHO INPUT FILE:
ECHO %1
SET INTEXT=%1
ECHO.
SET /P "LETTER=Letter? "
SET "REPLACE=%LETTER%asr"
SET TMP=tmp.txt
setlocal enabledelayedexpansion
FOR /F "tokens=1,* delims=¶" %%A IN ( '"TYPE %INTEXT%"') DO (
SET string1=%%A
SET modified=!string1:00asr=%REPLACE%!
echo !modified! >> %TMP%
)
PAUSE
I adapted this code. Looks like good code to me, but I'm like a blind man.
Now either the %TMP%s first-line [1-75] is required to determine whether there is any offset in the block
or the strings have to be compared, overwriting the line containing substring * Zasr[1-75] Zasr* with the same one from %TMP%;
or in the case of offset skipping a given amount of lines in %output% before overwriting the lines.
I'm not sure which option would be easier to implement or quicker to execute,
since I'm entirely failing at doing this.
The whole method should work something like this:
Input File
o <parameters> 00asr3 00asr3.hkx
o <parameters> 00asr4 00asr4.hkx
o <parameters> 00asr5 00asr5.hkx
User Input
Q
OUTPUT BEFORE
...
p Oasr75 Oasr75.hkx
p Qasr1 Qasr1.hkx
p Qasr2 Qasr2.hkx
p Qasr3 Qasr3.hkx
p Qasr4 Qasr4.hkx
p Qasr5 Qasr5.hkx
p Qasr6 Qasr6.hkx
....
OUTPUT AFTER
...
p Oasr75 Oasr75.hkx
p Qasr1 Qasr1.hkx
p Qasr2 Qasr2.hkx
o <parameters> Qasr3 Qasr3.hkx
o <parameters> Qasr4 Qasr4.hkx
o <parameters> Qasr5 Qasr5.hkx
p Qasr6 Qasr6.hkx
....
I managed to write the file renaming parts just fine; but this... I don't even.
I have been looking at various articles but due to not actually knowing any batch I'm not getting ahead with this.
1 Was very helpful, but I outright fail to compare strings correctly and can't seem to manage to assign them to variables.
Any help is appreciated. I might even understand what I'm doing wrong (which currently is most things).
I've solved it by myself.
Here's a shortened version of the script.
Cleaning input somewhat, changing the token in tmp, getting target parameters,
removing old target strings from file, merging files, deleting temps.
I'm confident this code isn't very good either way so further explanation seems unnecessary.
#ECHO OFF
SET _PACK=%1
SET "PATH=%~dp0"
SET "_LIST=in.txt"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "_ERROR=0"
:USERINPUT
IF %_ERROR%==1 (
ECHO INVALID INPUT: string too long.
SET "_ERROR=0"
)
IF %_ERROR%==2 (
ECHO INVALID INPUT: non-letter.
SET "_ERROR=0"
)
SET /P "LETTER=ENTER NEW BLOCK LETTER A-Z: "
ECHO "%LETTER%" SELECTED
IF NOT "%LETTER:~1,1%"=="" (
SET "_ERROR=1"
GOTO USERINPUT
)
if "%LETTER%" lss "A" (
SET "_ERROR=2"
GOTO USERINPUT
)
if "%LETTER%" gtr "Z" (
SET "_ERROR=2"
GOTO USERINPUT
)
SET "_STRING=%LETTER%asr"
' renaming files here
SET TMP=asr.tmp
DEL %TMP%
SET "_COUNT=0"
FOR /F "tokens=1,* delims=¶" %%A IN ( '"TYPE %_PACK%"') DO (
SET _LINE=%%A
SET _NEWLINE=!_LINE:0asr=%_STRING%!
ECHO !_NEWLINE!>> %TMP%
CALL SET /A _COUNT=_COUNT+1
)
ECHO NUMBER OF INPUT LINES: !_COUNT!
SET /P _OFFSET=< %TMP%
CALL SET _OFFSET=%%_OFFSET:*asr=%%
CALL SET _OFFSET=%%_OFFSET:~0, 2%%
CALL SET _OFFSET=%_OFFSET: =%
ECHO OFFSET: %_OFFSET%.
SET /A _END=_COUNT+_OFFSET-1
COPY /Y in.txt in.tmp
FOR /L %%X IN (%_OFFSET%, 1, %_END%) DO (
SET "_SEARCH=%_STRING%%%X "
ECHO DELETING OLD STRING : !_SEARCH!
FINDSTR /V /C:"!_SEARCH!" %_PACK% > in.tmp
del in.txt
ren "in.tmp" "in.txt"
)
TYPE %TMP%>> in.txt
DEL %TMP%
PAUSE
DEL %1
EXIT
I have some code which can crack numeric rar file passwords. The code just increments the value of a variable (starting from 0) and I use that to check against the password to unrar using unrar command.
But I want to generate strings for brute force attacks.
SET PASSWORD=0
:START
SET /A PASSWORD=%PASSWORD%+1
UNRAR E -INUL -P%PASSWORD% "%PATH%\%NAME%" "%DESTINATION%"
IF /I %ERRORLEVEL% EQU 0 GOTO CLOSE
GOTO START
:CLOSE
echo Password Cracked...
echo Password is %PASSWORD%
Here
%PATH% is path where rar file is located
%NAME% is name of rar file
%DESTINATION% is place where file is stored after UNRAR,
In my code DESTINATION is "%TEMP%\%RANDOM%"
By applying this I am able to get the password, but it is not useful for strings which contain alpha characters.
How do I generate strings starting from "a", so I am able to crack alphabetic passwords too?
I consider this a crazy idea to do in CMD/batch, but it at least sounded like an interesting challenge.
So, playing the part of the Professor from Gilligan's Island, I've decided to attempt to build a particle accelerator from coconuts.
Here's my entry. There might likely be a better solution using CMD/batch. The most favorable thing I can say about it is that it works. To adapt it to your purpose, change the ECHO statement inside the :INFINITE_LOOP to do something meaningful, like attempt to decompress the file and exit on success.
Here's a sample of the output as it runs:
'0'
'1'
...
'9'
...
'A'
'B'
...
'Y'
'Z'
'a'
'b'
...
'y'
'z'
'00'
'01'
...
'zy'
'zz'
'000'
'001'
...
'Car'
'Cas'
'Cat'
'Cau'
'Cav'
'Caw'
...
This solution should work with many characters (CHARSET contains all the characters to be used in the output string) with the exception of characters that cannot be assigned simply without escaping them in some manner (e.g. double quote, percent (maybe?), exclamation, ...).
The script doesn't completely clean up after itself (you'll have to manually erase %ITER_FILE%), but it isn't too messy.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "CHARSET=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghikjlmnopqrstuvwxyz"
:: ======================================================================
:: Setup
CALL :CONFIGURE_CHARSET "%CHARSET%"
REM ECHO MAX_INDEX: !MAX_INDEX!
REM SET
:: Put the smallest value in the file.
SET ITER_FILE=%TEMP%\ITERATOR_%RANDOM%.txt
ECHO.0>"%ITER_FILE%"
:: ======================================================================
:: Main Loop
:INFINITE_LOOP
CALL :READ_ITER "%ITER_FILE%" _ITER_CONTENTS
ECHO '!_ITER_CONTENTS!'
CALL :NEXT_ITER "%ITER_FILE%"
GOTO :INFINITE_LOOP
EXIT /B
:: "Increment" the contents of the "state variable" file.
:NEXT_ITER
SETLOCAL
SET "FILE=%~1"
SET "NEXT_FILE=%TEMP%\ITERATOR_NEXT_%RANDOM%.txt"
SET CARRY=1
FOR /F %%n IN (%FILE%) DO (
IF !CARRY! EQU 1 (
SET /A I_VALUE=%%n+1
IF !I_VALUE! GTR %MAX_INDEX% (
SET I_VALUE=0
SET CARRY=1
) ELSE (
SET CARRY=0
)
) ELSE (
SET I_VALUE=%%n
)
ECHO !I_VALUE!>>"!NEXT_FILE!"
)
REM Add a new digit place.
IF !CARRY! EQU 1 (ECHO.0>>"!NEXT_FILE!")
MOVE /Y "%NEXT_FILE%" "%FILE%" >NUL
ENDLOCAL
EXIT /B
:: Read the contents of the "state variable" file and translate it
:: into a string.
:: The file is a series of lines (LSB first), each containing a single
:: number (an index).
:: Each index represents a single character from the CHARSET.
:READ_ITER
SETLOCAL
SET "FILE=%~1"
SET "VAR=%~2"
SET VALUE=
SET _V=
FOR /F %%n IN (%FILE%) DO (
SET "VALUE=!VALUE_%%n!!VALUE!"
)
ENDLOCAL && SET %VAR%=%VALUE%
EXIT /B
:: Translate the index number to a character.
:TRANS_INDEX
SETLOCAL
SET "VAR=%~1"
SET "C=%~2"
SET IDX=
FOR /L %%i IN (0,1,%MAX_INDEX%) DO (
IF "!VALUE_%%i!"=="!C!" SET IDX=%%i
)
SET "TRANS=!VALUE_%%i!"
ENDLOCAL && SET "%VAR%=%TRANS%"
EXIT /B
:: This is ugly magic.
:: Create variables to hold the translation of an index to a character.
:: As a side effect, set MAX_INDEX to the largest used index.
:CONFIGURE_CHARSET
SET CONFIG_TEMP=%TEMP%\CONFIG_%RANDOM%.cmd
IF EXIST "%CONFIG_TEMP%" DEL /Q "%CONFIG_TEMP%"
CALL :WRITE_CONFIG "%CONFIG_TEMP%" "%~1"
REM Import all the definitions.
CALL "%CONFIG_TEMP%"
EXIT /B
REM Create a means to "add one" to a value.
:WRITE_CONFIG
SETLOCAL
SET "FILE=%~1"
SET "STR=%~2"
REM This is the "index" of the symbol.
SET "INDEX=%~3"
IF "!INDEX!"=="" SET INDEX=0
IF NOT "%STR%"=="" (
SET "C=!STR:~0,1!"
IF NOT "%~4"=="" (
SET "FIRST=%~4"
) ELSE (
SET "FIRST=!C!"
)
SET "D=!STR:~1,1!"
IF "!D!"=="" (
SET CARRY=1
SET "D=!FIRST!"
) ELSE (
SET CARRY=0
)
ECHO SET VALUE_!INDEX!=!C!>>"!FILE!"
SET /A NEXT_INDEX=INDEX+1
REM Recurse...
SET MAX_INDEX=!INDEX!
CALL :WRITE_CONFIG "!FILE!" "!STR:~1!" "!NEXT_INDEX!" "!FIRST!"
IF !INDEX! GTR !MAX_INDEX! SET MAX_INDEX=!INDEX!
)
ENDLOCAL && SET MAX_INDEX=%MAX_INDEX%
EXIT /B
Recursion does the job!
I know I'm a bit late, but I think this code works very well and also quite fast:
#echo off
title bruteforce
setlocal enableDelayedExpansion
echo:
echo Brute Force Attack:
echo -------------------
echo:
set /p input="Amount of digits: "
set /a depth=%input%-1
echo:
set /p possibleChars="Possible Characters: "
echo:
for /l %%y in (0, 1, %depth%) do (
set chars[%%y]=0
)
call :next 0
echo:
pause
exit
:next
setLocal
set /a d=%1
for %%x in (%possibleChars%) do (
set chars[%d%]=%%x
if %d% lss %depth% (
call :next !d!+1
) else (
set password=
for /l %%c in (0, 1, %depth%) do (
set password=!!password!!chars[%%c]!!
)
echo !password!
)
)
On my laptop it prints about 1500 combinations per second, and you can do what ever you want with the password-variable which I've just printed out!
IMPORTANT:
The first part of the program asks you for the length of the password to crack and possible characters when you run it!
You have to enter the possible characters with a space between each character, like this:
0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k...
I want to match a variable to part of the contents of another variable in batch. Here is some pseudo code for what I want to do.
set h= Hello-World
set f= This is a Hello-World test
if %h% matches any string of text in %f% goto done
:done
echo it matched
Does anybody know how I could accomplish this?
Based off of this answer here, you can use the FINDSTR command to compare the strings using the /C switch (modified from the linked answer so you don't have to have a separate batch file for comparing the strings):
#ECHO OFF
set h=Hello-World
set f=This is a Hello-World test
ECHO Looking for %h% ...
ECHO ... in %f%
ECHO.
echo.%f% | findstr /C:"%h%" 1>nul
if errorlevel 1 (
ECHO String "%h%" NOT found in string "%f%"!
) ELSE (
ECHO String "%h%" found in string "%f%"!
)
ECHO.
PAUSE
If the following conditions are met:
The search is case insensitive
The search string does not contain =
The search string does not contain !
then you can use:
#echo off
setlocal enableDelayedExpansion
set h=Hello-World
set f=This is a Hello-World test
if "!f:*%h%=!" neq "!f!" (
echo it matched
) else (
echo it did not match
)
The * preceding the search term is only needed to allow the search term to start with *.
There may be a few other scenarios involving quotes and special characters where the above can fail. I believe the following should take care of such problems, but the original constraints still apply:
#echo off
setlocal enableDelayedExpansion
set h=Hello-World
set f=This is a Hello-World test
for /f delims^=^ eol^= %%S in ("!h!") do if "!f:*%%S=!" neq "!f!" (
echo it matched
) else (
echo it did not match
)
Here's another way:
#echo off
set "h=Hello-World"
set "f=This is a Hello-World test"
call set "a=%%f:%h%=%%"
if not "%a%"=="%f%" goto :done
pause
exit /b
:done
echo it matched
pause
I'm using the following piece of code; to change something in a Cmakefile:
for /f %%j in (CMakeLists.txt) do (
if "%%j"=="Extensions_AntTweakBar" (
echo #Extensions_AntTweakBar >> temp.tmp
) else (
if "%%j"=="Extensions_Inspection" (
echo #Extensions_Inspection >> temp.tmp
) else (
if "%%j"=="Extensions_InspectionBar" (
echo #Extensions_InspectionBar >> temp.tmp
) else (
echo %%j >> temp.tmp
)
)
)
)
It seems to work, that is, it does change the selected lines, however, if theres a space on one line, it only gets that line till the space occurs.
Example:
SET( PROJECT_NAME "MyProject")
Only gets the string:
SET(
How am I supposed to get the full string then?
In your code you append a space at each line.
echo %%j[space]>> temp.tmp
Here you can remove it(works only with %%j), but normally it is better to set the redirection as prefix, like
>> temp.tmp echo %%j
With a normal variable the postfix variant could fail
set var=hallo2
echo %var%>temp.tmp
Expands to echo hallo2>temp.tmp or echo hallo 2> temp.tmp, so only the stderr would redirected.
The next problem are the keywords ON OFF /?, if your file contains such a word you get unexpected results, because the echo interprets these words.
[EDIT:] To solve this you can use echo(
>>temp.tmp echo(%%j
You can get empty lines (or lines with only whitespaces), you simply need to prefix them.
for /f "delims=" %%a in ('findstr /n ".*" qut.bat') do (
set var=%%a
setlocal EnableDelayedExpansion
echo(!var:*:=!
endlocal
)
The toggling of the DelayedExpansion is neccessary to preserve "!" and "^" characters
The default delimiters are space and tab. If you override the default delimiter, it should read the entire line with spaces in between
for /f "delims=#" %%j in (CMakeLists.txt) do
I set it to #, and it ignores space as delimiter and reads the entire line. You can set it a unique character that you know will not be in the text file.