I am trying to understand a script but I dont know how %\n% is used, I dont understand why it can stand behind a string -->
set getKey=%\n%
for %%# in (1 2) do if %%#==2 (%\n%
set key=%\n%
set inKey=%\n%
set keyTest=%\n%
^<^&9 set /p "inKey="%\n%
if defined inKey (%\n%
set inKey=!inKey:~0,-1!%\n%
for %%C in (!args!) do set /a keyTest=1^&if /i !inKey! equ %%~C set key=!inKey!%\n%
)%\n%
if not defined keyTest set key=!inKey!%\n%
set draw=%\n%
cls%\n%
for /l %%Y in (0,1,%height%) do echo(!line%%Y!%\n%
echo Speed = !Difficulty! !replay!%\n%
echo Time = !m!:!s!%\n%`
...(it goes further)
what is cls%\n% ??
if somebody understands me, please help me
THNX
the whole script -->
http://www.dostips.com/forum/viewtopic.php?f=3&t=4741
%\n% is the expansion of the environment variable \n. So you need to look where that is defined.
When you find it there is a comment explaining it:
:: define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
What is LF?
:: define LF as a Line Feed (newline) character
set ^"LF=^
^" Above empty line is required - do not remove
So LF is being set to a newline character. All that gubbins is just a long-winded way of doing something which is not easy to do in a CMD batch file.
%\n% is a normal environment variable.
Run this to see it work:
#echo off
set \n=a
set getKey=%\n%
echo "%getkey%"
pause
Related
I'm trying to create a command in the command prompt, but use arguments like you can do with a function in another language.
For example, you can create a batch file in the C:\Windows\System32 folder and execute it in the command prompt by typing its name, creating a "command." This is very simple, though, and simply runs whatever the batch file contains.
My command I made is called toolbx, which has different useful shortcuts in the command prompt. But, I want to execute different tools by typing something like toolbx 1. Here's what it might look like.
toolbx [input received changing what tool you want to use] (e.g. 1)
In toolbx.bat
if %inputRecieved% == 1 goto 1
I'm not the best at explaining, so another example in Python might be:
def functionWithArgs (tool)
Executed as:
functionWithArgs(1)
As another summary:
I'm trying to make a command used in the command prompt with a batch file
I want the batch file to have arguments defined when the command is run (like the python example) that can be used as variables in the batch file.
Thank you in advance!
It is your lucky day today, windows batch files do in fact support a feature called command-line parameters. Here is what you need to do:
set inputRecieved=%1
if "%inputRecieved%"=="1" goto label1
goto :eof
:label1
blabla...
Have fun coding!
P.S.
Please note that the correct spelling of the word is "received", not "recieved".
You can use the macro style invented by #jeb, #dbenham and DosTips user #Ed Dyreen:
Definitions:
#echo off
SETLOCAL DISABLEDELAYEDEXPANSION
::Definitions
( set LF=^
%= EMPTY =%
)
set ^"NL=^^^%LF%%LF%^%LF%%LF%^^"
The whole purpose is to create a multiline variable. See the batch newline variable hack
Main Macro:
::Macro
ENDLOCAL &^
set $MACRO.Toolbx=FOR %%a in (args main) do if "%%a" == "main" (%NL%
for %%A in (%payload%) do (%NL%
%= MAIN MACRO HERE, END LINES WITH NL =%%NL%
)%NL%
) ELSE SETLOCAL ENABLEDELAYEDEXPANSION ^& set args=,
exit /b
Save this as MACRO.Toolbx.bat. To use the macro inside your batch file:
call MACRO.Toolbx.bat
%$MACRO.Toolbx% COMMAND_LINE_ARGS
The macro uses a clever FOR loop to "catch" the arguments. Also, in order to catch arguments, DISABLEDELAYEDEXPANSION is necessary, which is inseparable from SETLOCAL. However, ENDLOCAL will destroy all user-defined variable in that range, but we need the newline definitions. Therefore, ENDLOCAL and the macro definition must be on the same line. This technique is called ENDLOCAL tunneling.
sure
[Complete path and file name] [Parameter1] [Parameter2] [and_so_on]
Is a space that separates parameters that can be expanded with %1 %2 %3...
You can expand all parameters with %* or up to 9 parameters individually
for example:
%windir%\system32\toolbx.cmd Tool_1
note the parameter beign passed is: Tool_1
in the example below is beign used at line 2 where %1 expands: Tool_1
setlocal EnableDelayedExpansion
set tool=%1
set argument_1=Have
set argument_2=a
set argument_3=Nice
set argument_4=Day
CALL :Function_%tool% argument_1 argument_2 argument_3 argument_4
:: after Function_Tool_1 ends by reading the next GOTO :EOF after its Label,
:: will return to read instructions after this line
::
pause&&exit
::
:Function_Tool_1
echo. %argument_1% %argument_2% %argument_3% %argument_4%
goto :EOF
::
::
NOTE:
When using CALL to call labels, you have to use a colon for example:
CALL :YourLabel
And after the label all the parameters or arguments separated with a space
for example:
CALL :YourLabel param1 param2 param3 parampampam etc
I think the syntax for labels is the same as for variables.
You have to use a GOTO :EOF to end a function or procedure
See you don't use a colon when going to the label using GOTO for example:
GOTO YourLabel
but when using CALL is different, that is explained better typing:
EXIT /?
GOTO /?
& is used to separate instructions
&& is used to separate instructions inside a batch file as toolbx.cmd
Also note in the example above:
%1 %2 %3 and %4 along the function could expand the variable name, for example:
echo. %1 %2 %3 %4
would echo: argument_1 argument_2 argument_3 argument_4
and using SETLOCAL EnableDelayedExpansion
!%1! could expand the value of the variable, for example:
echo. !%1! !%2! !%3! !%4!
would echo: Have a Nice Day
A technique has been developed using for loops that allows arguments to be captured when a variable is expanded - Batch Macros.
An outer for loop is used, which on the first iteration assigns a variable containing the argument values, and the inner loop/s proccess and act upon those values.
#echo off
Set "Macroname=For %%n in (1 2)Do if %%n==2 (Echo(!Args!)Else Set args="
Setlocal EnableDelayedExpansion
%Macroname% Hello World
The technique requires defining the macro variable in an environment where Delayed expansion is disabled, then using Setlocal EnableDelayedExpansion to enable the macro. ( Unless of course all ! expansion symbols are correctly escaped during macro definition for an environment where delayed expansion is enabled. )
Below is a template for batch macro's that builds an Args array and and proccesses switches that trail arguments. The purpose of the template is to allow quick scripting of advanced functions by having all the argument and switch handling logic ready to go, so that the meat of the function is all that needs to be scripted.
Args are returned to the array $Macroname_args[!$Macroname_args[i]!] where:
!$Macroname_args[i]! is a 0 indexed count of args.
Switches are returned in associated variables using the switch string as the index IE:
%MacroName% /A
Results in: !$Macroname_Switch[A]!==true
Or if a subarg is supplied:
%MacroName% /A sub arg
Results in: !$Macroname_Switch[A]!==sub arg
The macro uses Substring modification to seperate switches from args and process switches.
As such, arg or switch values containing the following characters:
= * / "
should be supplied in a substituted form:
{EQ} {AS} {FS} {DQ}, which are replaced using substitution built into the macro.
#Echo off
(Set \n=^^^
%= \n macro newline variable. Do not modify =%)
(Set LF=^
%= LF newline variable. Do not modify =%)
:# Example Switches for demonstrating concept. List used twice within macro switch handling. Define outside macro to
:# simplify maintainance.
Set $MacroName_Switches="A" "B" "C" "D" "E" "Def"
Set $MacroName=For %%n in (1 2)Do if %%n==2 (%\n%
For /F "Tokens=1,2 Delims==" %%G in ('Set "$Macroname_Arg[" 2^^^> nul')Do Set "%%~G="%\n%
For %%G in ( %$MacroName_Switches% )Do Set "$MacroName_Switch[%%~G]="%\n%
If not "!$MacroName_args:* /=!" == "!$MacroName_args!" (%\n: build $MacroName.Args[!$MacroName_arg[i]!] array if args present =%
Set "$MacroName_leading.args=!$MacroName_args:*/=!"%\n%
For /F "Delims=" %%G in ("!$MacroName_leading.args!")Do Set "$MacroName_leading.args=!$MacroName_args:/%%G=!"%\n%
Set ^"$MacroName_args=!$MacroName_args:"=!"%\n%
Set "$MacroName_arg[i]=0"%\n%
For %%G in (!$MacroName_leading.args!)Do (%\n%
Set /A "$MacroName_arg[i]+=1"%\n%
Set "$MacroName_arg[!$MacroName_arg[i]!]=%%~G"%\n%
For %%i in ("!$MacroName_arg[i]!")Do (%\n%
Set "$MacroName_arg[%%~i]=!$MacroName_arg[%%~i]:{FS}=/!"%\n%
Set "$MacroName_arg[%%~i]=!$MacroName_arg[%%~i]:{AS}=*!"%\n%
Set "$MacroName_arg[%%~i]=!$MacroName_arg[%%~i]:{EQ}==!"%\n%
Set ^"$MacroName_arg[%%~i]=!$MacroName_arg[%%~i]:{DQ}="!"%\n%
)%\n%
)%\n%
) Else (%\n: remove doublequotes from args before switch processing switches =%
Set ^"$MacroName_args=!$MacroName_args:"=!"%\n%
)%\n%
Set "$MacroName_LastSwitch="%\n%
For /L %%L in (2 1 4)Do If "!$MacroName_LastSwitch!" == "" (%\n%
If "!$MacroName_Args:~-%%L,1!" == " " Set "$MacroName_LastSwitch=_"%\n%
If "!$MacroName_Args:~-%%L,1!" == "/" (%\n: Flag last switch true if no subargs; Works for character switches of up to 3 characters =%
For /F "Delims=" %%v in ('Set /A "%%L-1"')Do Set "$MacroName_Switch[!$MacroName_Args:~-%%v!]=true"%\n%
If not "!$MacroName_Args:/?=!." == "!$MacroName_Args!." Set "$MacroName_Switch[help]=true"%\n%
Set "$MacroName_Args=!$MacroName_Args:~0,-%%L!"%\n%
Set "$MacroName_LastSwitch=_"%\n%
)%\n%
)%\n%
For %%G in ( %$MacroName_Switches% )Do If not "!$MacroName_args:/%%~G =!" == "!$MacroName_args!" (%\n%
Set "$MacroName_Switch[%%~G]=!$MacroName_Args:*/%%~G =!"%\n%
If not "!$MacroName_Switch[%%~G]:*/=!" == "!$MacroName_Switch[%%~G]!" (%\n%
Set "$MacroName_Trail[%%~G]=!$MacroName_Switch[%%~G]:*/=!"%\n%
For %%v in ("!$MacroName_Trail[%%~G]!")Do (%\n%
Set "$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]: /%%~v=!"%\n%
Set "$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]:/%%~v=!"%\n%
)%\n%
Set "$MacroName_Trail[%%~G]="%\n%
If "!$MacroName_Switch[%%~G]:~-1!" == " " Set "$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]:~0,-1!"%\n%
If "!$MacroName_Switch[%%~G]!" == "" Set "$MacroName_Switch[%%~G]=true"%\n%
If not "!$MacroName_Switch[%%~G]!" == "" If not "!$MacroName_Switch[%%~G]!" == "true" (%\n%
Set "$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]:{FS}=/!"%\n%
Set "$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]:{AS}=*!"%\n%
Set "$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]:{EQ}==!"%\n%
Set ^"$MacroName_Switch[%%~G]=!$MacroName_Switch[%%~G]:{DQ}="!"%\n%
)%\n%
)%\n%
)%\n: Insert Switch Assessment Below. Use conditional testing of valid switches to enact macro functions before $MacroName_args assignment =%
REM INSERT COMMANDS BETWEEN THE ABOVE AND BELOW LINES TERMINATING EACH WITH \n VARIABLE %\n%
%= EXAMPLE. Remove this line. =% Echo(!LF!Example: %%$Macroname%%!$Macroname_args!%\n%
%= EXAMPLE. Remove this line. =% Set $Macroname_Arg[%\n%
%= EXAMPLE. Remove this line. =% Set $Macroname_Switch[%\n%
%= ESCAPE AMPERSANDS AND REDIRECTION CHARACTERS DURING MACRO DEFINITION. =%) Else Set $MacroName_args=
Setlocal enableDelayedExpansion
:# Proof of concept
%$Macroname% "{AS} param 1 {EQ} {DQ}https:{FS}{FS}stackoverflow.com{FS}posts{FS}60793679{DQ}" "param 2" /C one /D 12 /Def
%$Macroname% /B a b /E /Def "hello world & ^! > < | %%" /A 1 + 2 {EQ} 3 /Undefined switch
Alright, so I'm trying to read all lines from a text file. My current way is:
FOR /F "delims=0123456789 tokens=1,*" %%F IN ('find /v /n "" ^< myFile.bat') DO (
SET line = %%G
:: ^ Syntax errors at this line
SET line=!line:~1!
:: Yes, I have delayed expansions enabled due to a lot of fors and ifs needed
)
Basically the input file is another batch file which also contains the exact same code as above and other code with <, >, ^ etc. Once I read a line, it's basically impossible to use %%G as it will expand to stuff like:
SET line=ECHO Hello >> someFile
or
SET line=FOR /L %%G IN (1,1,5) ( SET "line=ECHO Hello %%G" & call :something & >nul SET /P =. )
Which will obviously not work. I've tried many workarounds (all have failed), including:
SET line="%%G
Which (most of the time) works, but from there using is with basically anything is near-impossible, even with something like:
:fixLine
SET line=%line:^=^^^^%
SET line=%line:<=^^^<%
SET line=%line:>=^^^>%
SET line=%line:'=^^^'%
SET line=%line:~2%
GOTO :returnFixLine
But all methods fail in some case or another. How can I read a file containing a batch script from another batch script, including special characters?
EDIT:
Doing
SET "line=%%G"
won't work, as %%G can contain quotes, and even if it doesn't, carets are still special in quotes:
SET "line=ECHO ^<Hello^>"
will turn into
SET "line=ECHO <Hello>"
Also, lines containing exclamation marks will get expanded too.
The first problems are the spaces in set line = %%G, as you set the variable line<space> instead of line.
And you prefix to the content a space.
You should use set line=%%G instead, but even that produces sometimes problems, when spaces are behind the %%G they are appended.
The best way is to use the extended SET syntax set "line=%%G".
Btw. There exists only one special charcter which can fail with a FOR-parameter expansion, that is the exclamation mark when delayed expansion is enabled.
The solution is to toggle delayed expansion.
setlocal DisableDelayedExpansion
FOR /F "delims= tokens=*" %%F IN ('find /v /n "" ^< myFile.bat') DO (
SET "line=%%F"
setlocal EnableDelayedExpansion
SET "line=!line:*]=!"
echo(Testoutput: !line!
endlocal
)
I come to find some guidance on accomplishing the following:
I have a variable with content like this:
varname = asdfiuytgy12$gggsy22.oihbcxew
or
varname = oiujedc$thisisit.oiju
which $ and . are exactly my partters and I need to get what is within them so gggsy22 or thisisit.
I need to use batch to create a simple bat file. I hope someone can provide some guidance.
Edit - (from comment section)
Actually a friend of mine helped and it did work but with a quite amount of lines:
Set "sstr=$"
SET stemp=%nameVar%&SET pos=0
:loop
SET /a pos+=1
echo %stemp%|FINDSTR /b /c:"%sstr%" >NUL
IF ERRORLEVEL 1 (
SET stemp=%stemp:~1%
IF DEFINED stemp GOTO loop
SET pos=0
)
Set "pos1=%pos%"
Set "sstr=."
SET stemp=%nameVar%&SET pos=0
:loop
SET /a pos+=1
echo %stemp%|FINDSTR /b /c:"%sstr%" >NUL
IF ERRORLEVEL 1 (
SET stemp=%stemp:~1%
IF DEFINED stemp GOTO loop
SET pos=0
)
Set "pos2=%pos%"
set /a "pos2=%pos2%-%pos1%-1"
call set env=%%nameVar:~%pos1%,%pos2%%%
#echo off
set "varname=asdfiuytgy12$gggsy22.oihbcxew"
for /f "tokens=2 delims=$." %%a in ("%varname%") do set "sub=%%a"
The following works in nearly any situation. The only thing that could break the code is if the string contains a quote " followed by a poison character like &, |, etc.
#echo off
setlocal
set "str=oiujedc$thisisit.oiju"
:: Verify string exists and has the proper format
echo "%str%"|findstr "\$.*\." >nul || (echo Value not found & exit /b)
:: Extract the value
:: The extra "x" is needed in case there is no character between $ and .,
:: in which case the result should be No Value (result variable not defined)
for /f "delims=." %%A in ("x%str:*$=%") do set "val=%%A"
set "val=%val:~1%"
:: Show the result
echo value = "%val%"
A bullet proof variant can be made by incorporating delayed expansion.
In batch file, to define a function you put a : sign and then the name of the function
For example:
:func
copy "test.txt" "D:\test"
Then when you want to call the function you use goto:
goto func
Is there a way to do that without a batch file? To define a function from the cmd?
You could make a macro.
set "func=copy "test.txt" "D:\test""
Then to execute it,
%func%
Batch (cmd.exe) doesn't knows functions at all.
With labels you can build a construct that works similar to functions and for returning use exit /b ( or goto :eof),
but in reality this isn't a function.
But labels can only be used inside of batch files!
At the other side you could use macros, these are variables with code.
Also no real functions, but can work like one.
Usage of a macro (in this case to get the string length):
set "var=abcdef"
%strlen% var
And to build the macro you only need to copy this into your command prompt
cmd /v:on
set LF=^
::Above 2 blank lines are required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
:::: StrLen pString
set strLen=#for /L %n in (1 1 2) do #if %n==2 (%\n%
for /F "tokens=1,2 delims=, " %1 in ("!argv!") do #(%\n%
set "str=A^!%~1^!"%\n%
set "len=0"%\n%
for /l %A in (12,-1,0) do #(%\n%
set /a "len|=1<<%A" ^> nul %\n%
for %B in (^^!len^^!) do #if "^!str:~%B,1^!"=="" set /a "len&=~1<<%A" ^> nul%\n%
)%\n%
for %v in (^^!len^^!) do #if "%~2" neq "" (set "%~2=%v") else echo %v%\n%
) %\n%
) ELSE set argv=,
But macros have a tendency to become nasty.
Or you could read DosTips: Executing GOTO/CALL in a cmd.exe, it's a little bit advanced technic
:func is not a function but label in batch file. I.e. point for goto. There is no return like in subroutine/function.
The following is the batch script i have written
#echo off
setlocal enabledelayedexpansion
set finalcontent=
For /F "tokens=1-2* delims= " %%I in (abc.txt) do (
IF %%J EQU MAJORVER (
set currentline=%%I %%J %1
set finalcontent=!finalcontent!!currentline!
) ELSE IF %%J EQU MINORVER (
set currentline=%%I %%J %2
set finalcontent=!finalcontent!!currentline!
) ELSE IF %%J EQU BUILDNUM (
set currentline=%%I %%J %3
set finalcontent=!finalcontent!!currentline!
) ELSE (
set currentline=%%I %%J %%K%NL%
set finalcontent=!finalcontent!!currentline!
)
)
echo %finalcontent%>>xyz.txt
I want a newline character appended at the end of every occurence of the variable currentline. Can anyone guide me on this?
You can create a real newline character and assign it to a variable.
setlocal EnableDelayedExpansion
set LF=^
rem TWO empty lines are required
echo This text!LF!uses two lines
The newline best works with delayed expansion, you can also use it with the percent expansion, but then it's a bit more complex.
set LF=^
rem TWO empty lines are required
echo This text^%LF%%LF%uses two lines
echo This also^
uses two lines
How it works?
The caret is an escape character, it escapes the next character and itself is removed.
But if the next character is a linefeed the linefeed is also removed and only the next character is effectivly escaped (even if this is also an linefeed).
Therefore, two empty lines are required, LF1 is ignored LF2 is escaped and LF3 is neccessary to finish the "line".
set myLinefeed=^<LF1>
<LF2>
<LF3>
Hints:
It's often better to use a quite different format of the newline variable definition,
to avoid an inadvertently deletion of the required empty lines.
(SET LF=^
%=this line is empty=%
)
I have removed to often one of the empty lines and then I searched forever why my program didn't work anymore.
And the paranoid version checks also the newline variable for whitespaces or other garbage.
if "!LF!" NEQ "!LF:~0,1!" echo Error "Linefeed definition is defect, probably multiple invisble whitespaces at the line end in the definition of LF"
FOR /F "delims=" %%n in ("!LF!") do (
echo Error "Linefeed definition is defect, probably invisble whitespaces at the line end in the definition of LF"
)
You can define the newline as follows:
set newline=^& echo.
Then, you can use the newline in the echo-statement, like this: (not applicable in the outlined situation, however)
echo %finalcontent%%newline%
or you can use the newline in each set-statement, like this: (mind the extra caret)
set finalcontent=!finalcontent!!currentline!^!newline!
or similarly:
set currentline=%%I %%J %1^%newline%