In my batch I want to copy a variable amount of source- to target destinations.
I want to define like this:
#setlocal EnableDelayedExpansion
set source1="C:\folder1"
set target1="f:\folder1"
set source2="C:\folder2"
set target2="f:\folder2"
...
set sourcen="C:\foldern"
set targetn="f:\foldern"
Dependently from a defined amount of folders
set numFolder=5
I want to go through the folders in a loop:
set /a COUNT=0
:LOOP
echo %COUNT%
set /a COUNT+=1
rem write the NAME of the parameter variable (source1,source2 etc.) in nameor
set "nameor=source%COUNT%"
rem write the VALUE of the parameter variable (source1,source2 etc.) into origin ("C:\folder1", "C:\folder2")
set "origin=%nameor%"
echo %origin%
if %COUNT% lss %numFolder% goto LOOP
When I show
echo %nameor%
I get what I expectet: source1, source2 etc.
but
echo %%%origin%%%
only provides
source1
instead of the expected value
"C:\folder1"
I thought, that I could resolve this by using DelayedExpansion but what did I miss?
To avoid confusion for me, I change the "origin" to "source". E.g. set "origin=%nameor%" changed to set "source=%nameor%".
To print out "C:\folder1" to "C:\foldern", you should use echo !%source%!, else you will just see "source1" to "sourcen".
Your problem is just about array element management. Try this:
#echo off
setlocal EnableDelayedExpansion
rem Define the two arrays
set i=0
for %%a in ("C:\folder1=f:\folder1"
"C:\folder2=f:\folder2"
"C:\foldern=f:\foldern") do (
set /A i+=1
for /F "tokens=1,2 delims==" %%b in (%%a) do (
set source!i!="%%a"
set target!i!="%%b"
)
)
rem Show up to numFolder elements of both arrays
set numFolder=5
for /L %%i in (1,1,%numFolder%) do (
echo %%i- Source%%i=!source%%i!, Target%%i=!target%%i!
)
The first part is equivalent to your series of individual element assignments. In this way is easier to add new pairs of values.
For further description on array management in Batch files, see: Arrays, linked lists and other data structures in cmd.exe (batch) script
Related
I was recently given the advice to export variables from a batch script to a text file using
set $>savefile
and returning said variables upon another startup using
for /f "delims=" %%a in (savefile) do set %%a
In implementation, this is not creating a file with the variables, resulting in error in the script, which closes the batch. To remedy the closing, I created a check to display an error message, but still cannot get the script to export variables into a file.
Variables
::Variables
set Location=Und
set Name=Und
set Gender=Und
set Age=Und
set Gold=0
set Hunger=Satisfied
set Illness=None
set Wounds=None
set CHP=10
set MHP=10
set CMP=0
set MMP=0
set DMG=(%STR%/5)+%RTWPDMG%
set DFN=0+%HeadAR%+%NeckAR%+%Shoulder%+%Chest%+%Glove%+%Leg%+%Feet%
set INT=1
set DEX=1
set STR=1
set Head=----
set Shoulder=----
set Neck=----
set Chest=Shirt
set Glove=----
set Leg=Pants
set Feet=Shoes
set LTWP=----
set RTWP=----
goto Start
Save script
::Save
:Save
cls
set $Location=%Location%
set $Name=%Name%
set $Gender=%Gender%
set $Age=%Age%
set $Gold=%Gold%
set $Hunger=%Hunger%
set $Illness=%Illness%
set $Wounds=%Wounds%
set $CHP=%CHP%
set $MHP=%MHP%
set $CMP=%CMP%
set $MMP=%MMP%
set $DMG=%DMG%
set $DFN=%DFN%
set $INT=%INT%
set $DEX=%DEX%
set $STR=%STR%
set $Head=%Head%
set $Shoulder=%Shoulder%
set $Neck=%Neck%
set $Chest=%Chest%
set $Glove=%Glove%
set $Leg=%Leg%
set $Feet=%Feet%
set $LTWP=%LTWP%
set $RTWP=%RTWP%
set $>%Name%_Savefile.txt
cls
echo SAVED
echo.
echo.
pause
Goto Start
And the load script
::Select Character to Load
:LoadError
Echo INVALID NAME
echo.
echo.
echo.
echo.
goto LoadSelect1
:LoadSelect
cls
goto LoadSelect1
:LoadSelect1
set /p Name=Enter character to load:
goto Load
:Load
cls
if EXIST %Name%_Savefile.txt goto LoadSuccess
goto LoadError
:Load
for /f "delims=" %%a in %Name%_Savefile.txt do set %%a
goto Stats
Am I missing something? I'd like all variables beginning with $ to be targeted without needing to list each one.
Bonus Question:
If I use $Variable for the original variables, are they still called using %Variable%? If so, it'd cut down quite a bit of clutter.
--I realize batch is a sub-optimal language to script in, but it is the only one I am familiar with. I am currently working on lua and C++, and plan on practicing the two by converting the batch file later.
EDIT: The file is created, but only contains $ in line 1 and nothing else. I assume I have misunderstood the use of the variable export command.
It is quite simple say if you had %test% as your variable. (But it can be %% any thing) You should then do this:
echo %test%
echo %test% >nameofyourtextfile.txt
Then to read the you should use:
for /f "delims=" %%x in (nameofyourtextfile.txt) do set "test=%%x"
echo %test%
works for the first line of the text file and >> sends the variable to last line. So you could use these like so:
echo %test1% > nameofyourtextfile.txt
echo %test2% >> nameofyourtextfile.txt
echo %test3% >> nameofyourtextfile.txt
To load from different lines you would use:
for /F "tokens=1,2,3" %%i in (nameofyourtextfile.txt) do call :process %%i %%j %%k
goto thenextstep
:process
set test1=%1
set test2=%2
set test3=%3
You could add more tokens like so:
for /F "tokens=1,2,3,4,5" %%i in (nameofyourtextfile.txt) do call :process %%i %%j %%k
goto thenextstep
:process
set test1=%1
set test2=%2
set test3=%3
set test4=%4
set test5=%5
If you do it the way you posted, what you have is (just a extract)
in your main code set Wounds=None
in your save code set $Wounds=%Wounds% set $>filename
in your load code for %%a .... set %%a that gets translated to set $Wounds=None
At the end, you have not assigned a loaded value to %Wounds%, so an aditional set Wounds=%$Wounds% is needed.
I think the advice on using $ you received was an advice on using a common prefix to all the variables you want to save, so, you can send them and load them from a file with little effort. You can use $ or whatever other thing you want as long as it is a valid sintax and you change all the variables that you want save/load to that sintax.
By example
call :initializeCharacter
....
call :save
....
call :load
:initializeCharacter
set "ch.Name=Und"
set "ch.Gender=Und"
....
exit /b
:save
set ch.>"c:\savedGames\save.txt"
exit /b
:load
for /f "usebackq delims=" %%a in ("c:\savedGames\save.txt") do set "%%a"
exit /b
When the load function gets called, the variables (named ch.whatever and saved as ch.whatever) get overwritten on file read. That way, the variables in your code, what you save and what you load, all, have the same names. No need to set $myVar=%myVar% on save or set myVar=%$myVar%on load
And use $, ch., .... or whatever prefix you prefer in all the variables that needs to be saved/loaded in a block. What you don't want to save/load should have names that do not match the prefix used in the set prefix>file. Better option is to use different prefixes for different domain/level/conceptual element/...
How can I increment part of a variable name?
EG. i want to increment
filename holds something like mmddyyyy-prev01-Database.mdb
and I'm trying to rename it to mmddyyyy-prev02-Database.mdb
With the code
Setlocal EnableDelayedExpansion
set /a nextFileName=!fileName:~0,13!!fileName:~13!+1
and I get the error
Missing operator.
I am using this to make a batch sub that will recursively rename the prevXX items so that the newest one is always prev01. I'm also doing regular setlocal in my method to keep the variables from getting mixed up between the deeper calls
I'm going the hard way:
#ECHO OFF &SETLOCAL disableDelayedExpansion
FOR /f "delims=" %%x IN ('DIR /b /a-d /o-n *-prev*-Database.mdb') DO (
FOR /f "tokens=1-3*delims=v-" %%a IN ("%%~x") DO (
FOR /f "tokens=*delims=0" %%e IN ("0%%c") DO (
FOR /f %%f IN ('SET /a %%e+1') DO (
IF %%f LEQ 9 (
ECHO REN "%%~x" "%%~a-%%~bv0%%~f-%%~d"
) ELSE (
ECHO REN "%%~x" "%%~a-%%~bv%%~f-%%~d"
)
)
)
)
)
Just remove the ECHOs to make it working.
SET /A won't allow you do this.
You'll have to break up into two lines, like this:
SET BaseFileName=!FileName:~0,13!
SET /A Counter=!FileName:~13!+1
Then, put the pieces back together:
SET NextFileName=%BaseFileName%%Counter%-Database.mdb
NOTE: This will not handle your leading 0...you'll have to write more code for that.
...
set filename=mmddyyyy-prev01-Database.mdb
call :nextname
ren %filename% %newname%
...
:nextname
set /a newname=1%filename:~13,2%+1
set newname=%filename:~0,13%%newname:~-2%%filename:~15%
goto :eof
Whether you'd use ren %filename% %newname% or ren !filename! !newname! is a matter of context. You've posted insufficient code to be certain. If, as I suspect, you are executing the ren in a loop, then you would need the !var! form and delayedexpansion (with which you appear familiar.) Within the subroutine :nextname, the %var% form should be used.
but remember that you need to rename your existing files in reverse-alphabetical order, so
mmddyyyy-prev03-Database.mdb becomes mmddyyyy-prev04-Database.mdb
mmddyyyy-prev02-Database.mdb becomes mmddyyyy-prev03-Database.mdb
mmddyyyy-prev01-Database.mdb becomes mmddyyyy-prev02-Database.mdb
I have a variable "var1" with contents of "sharp=soothe"
var1=sharp=soothe
How do I create a new variable using only var1 contents to get this
sharp=soothe
I want to use the set command somehow like this
set %var1%=
but I can't get further than this. I hope I don't have to search for strings before and after the = sign. I thought there would be a faster way than that.
OK, I am so close. I found some other code I'm using and this nearly works for an infinite number of variables but the set command syntax is wrong again.
set var1=unfilter=rem
set var2=mdegrain=rem
set n=0
:parseArgs2
set /a n+=1
if defined var%n% (
set %var%n%%
shift /1
goto :parseArgs2
)
Just remove one character from your attempt :-)
set %var1%
If you have an "array" of variables: var1, var2, ... var20, then you can use a FOR /L loop with delayed expansion:
setlocal enableDelayedExpansion
rem define your variables here ...
for /l %%N in (1 1 20) do set !var%%N!
Or if you have a series of randomly named variables, a simple FOR will do:
setlocal enableDelayedExpansion
rem define your variables here ...
for %%V in (varA varB varC varD) do set !%%V!
update in response to add-on question
I don't see why you are using SHIFT, unless there is other code you haven't shown. I removed the SHIFT.
set var1=unfilter=rem
set var2=mdegrain=rem
set n=0
:parseArgs2
set /a n+=1
if defined var%n% (
call set %%var%n%%%
goto :parseArgs2
)
or
setlocal enableDelayedExpansion
set var1=unfilter=rem
set var2=mdegrain=rem
set n=0
:parseArgs2
set /a n+=1
if defined var%n% (
set !var%n%!
goto :parseArgs2
)
Try this:
set var1=sharp=soothe
for /f "tokens=*" %%a in ("%var1%") do set %%a
echo %sharp%
or just:
for %%a in ("%var1%") do set %%a
Perhaps is this what you want?
#echo off
setlocal EnableDelayedExpansion
set var1=unfilter=rem
set var2=mdegrain=rem
set var10=resize=rem
for /F "tokens=1* delims==" %%a in ('set var') do set %%b
In this method does not matter the number of defined variables nor its order; all defined variables are always processed.
EDIT: Below is the output when an ECHO command is placed before the set %%b:
set unfilter=rem
set resize=rem
set mdegrain=rem
I am writing a file to remove spaces from filenames in a folder and then put the result in a .txt file. I just get a result of "Echo is on." over and over.
This is what I have so far:
#echo ON
SET LOCAL EnableDelayedExpansion
For %%# in (*.*) do (
SET var=%%~n#
Set MyVar=%var%
set MyVar=%MyVar: =%
echo %MyVar%>>text.txt
)
Can someone tell me whats wrong?
Removing all spaces (not just leading and trailing) can be done without using setlocal enabledelayedexpansionwith the following line:
set var=%var: =%
This works by replacing all spaces in the string with the empty string.
Source: DOS - String Manipulation
The reason why you are getting ECHO is on. is because delayed expansion was not used, which caused the value of %var% and %MyVar% to be inserted before the for command is run, and since they were not defined at the start, empty variables were inserted in. When the echo %MyVar%>>text.txt was run, it was interpreted as echo >>text.txt. When echo is run without any arguments, it outputs whether echo is on or off, which is what you get in text.txt.
To fix the problem, you have to do two things:
First, there is something wrong with your second line. There is no space between set and local in setlocal. The second line should be SETLOCAL EnableDelayedExpansion.
Second, to use delayed expansion, you have to replace all %s in each variable with !, like !var! instead of %var%.
End result:
#echo ON
SETLOCAL EnableDelayedExpansion
For %%# in (*.*) do (
SET var=%%~n#
Set MyVar=!var!
set MyVar=!MyVar: =!
echo !MyVar!>>text.txt
)
You actually do not need to use a temporary variable in this case, you can just do SET MyVar=%%~n# and skip to set MyVar=!MyVar: =!.
The wrong thing is you've enabled the variable expansion (you wroted it bad...) and also you are not using it, when you use enabledelayedexpansion you need to write the variable names as this: !Variable! instead of this else: %Variable%
But you don't need to use it with this code:
#echo ON
For %%# in (*) do (
SET "var=%%~n#"
Call Set "MyVar=%%var: =%%"
Call echo %%MyVar%%>>text.txt
)
Run the following batch in the folder holding the files to be renamed
#echo off
setlocal enabledelayedexpansion
for %%j in (*.*) do (
set filename=%%~nj
set filename=!filename=.=_!
set filename=!filename= =_!
if not "!filename!"=="%%~nj" ren "%%j" "!filename!%%~xj"
)
you just need to add the print to txt
The set var=%var: =% did not work for me.
So I tried with success for a number the following code:
set /a var-=1 & set /a var+=1
This is the new Script and it Still Doesn't Work
I Get The syntax of the command is incorrect.
on FOR /F "USEBACKQ tokens=*" %%A IN (TYPE "C:\Windows\System32\tasks\at!num! ^| FIND "Command") DO (
SETLOCAL ENABLEDELAYEDEXPANSION
set num=1
:START
IF NOT EXIST "C:\Windows\System32\tasks\at%num%" (GOTO:EOF)
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "C:\Windows\System32\tasks\at!num! ^| FIND "Command"`) DO (
set var=%%A
ECHO %var%
SET /a num=%num%+1
PAUSE
)
GOTO:START
To understand your code, I'm going to break it down into logic first then try to solve it. Let me know if I miss a detail...
Set num var to 0
Begin :Loop
set num var to its current value ::NOT NEEDED - You've specified this prior to the GOTO
increment num var by +1
if myfolder\at* file exists then read at%num% and find a string then output that line to %tmp%\1.txt ::Need quotations on file location.
set F var to the line stored in %tmp%\1.txt
set F="%%F: =%%" ::Please explain what you are trying to do with this command.
set F to start on 10th character and remove the last 11 characters from the line.
echo the variable
If it doesn't exist, exit, but if it does return to :Loop
You should tell us what you are attempting. If it is as simple as saving a variable from a text file output, set F=<file.txt will work. If it didn't, then something happened prior to that command. Still... what is set F="%%F: =%%"?
Unless you are using a FOR loop variable, there is no need to use %% on each end of the variable.
If this were a FOR loop, it would look like this:
SETLOCAL ENABLEDELAYEDEXPANSION
set num=1
:START
IF NOT EXIST "myFolder\at%num%.txt" (GOTO:EOF)
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "myFolder\at%num%.txt" ^| FIND /i "string"`) DO (
PAUSE
SET var=%%A
ECHO !var!
PAUSE
SET var=!var: =!
ECHO !var!
PAUSE
SET var=!var:~10,-11!
ECHO !var!
PAUSE
SET /a num=!num!+1
ECHO !num!
PAUSE
)
GOTO:START
One good practice to check if commands are working, such as SET, insert an ECHO on the variable and a PAUSE right after each time you believe the variable should be changed. This will track what has changed on the variable so you can see if your command was correct and the changes were made.
I'd suggest using Batch's inbuilt function for loops, see here.
Conditionally perform a command for a range of numbers
Syntax
FOR /L %%parameter IN (start,step,end) DO command
Or maybe iterating over files in a folder would be better for what you are trying to do?
Loop through files (Recurse subfolders)
Syntax
FOR /R [[drive:]path] %%parameter IN (set) DO command
Or iterating over file contents?
Loop command: against a set of files - conditionally perform
a command against each item.
Syntax
FOR /F ["options"] %%parameter IN (filenameset) DO command
FOR /F ["options"] %%parameter IN ("Text string to process") DO command
This site has plenty of examples here which should point you in the right direction.
There are a few issues with your code, I've amended as follows to get the variable populated with the contents of the temp file.
set num=0
:Loop
set /a num=%num%+1
if exist "myFolder\at*" (
TYPE "myFolder\at%num%" | FINDSTR "\<Command\>" > "%temp%\1.txt"
set /P F=<"%TEMP%\1.txt"
Echo %F%
Pause
)
I don't know if this is the problem, but have you tried enabling:
setlocal enabledelayedexpansion
Then, inside the loop (or the IF(...)), you use !foo! to signify environment variables instead of %foo%.
See setlocal /? and set /? for more information.