Windows Cmd Loop name and create folders - windows

I'm trying to figure out how to create a certain number of folders in a Windows batch file. I want to ask the user how many folder they want, and then use that collected number to loop the asking for names of those folders and make them. Here is what I have so far:
pushd C:\Users\%username%\Desktop
set /p FolderLoop="How many folders?: "
for /l %%x in (1, 1, %FolderLoop%) do (
set /p folder="Folder: " %%x
md %folder% %%x
)
The problem I keep having is that I can not make the folders with the proper collected names. The closest I have gotten so far is creating the right amount of folders, but with sequential numeric names (1,2,3, etc.) based om the FolderLoop variable.

You need to read any of the hundreds of responses on SO with regard to delayedexpansion.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Within a block statement (a parenthesised series of statements), REM statements rather than the broken-label remark form (:: comment) should be used because labels terminate blocks, confusing cmd.
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.

You need delayed expansion:
setlocal enabledelayedexpansion
pushd C:\Users\%username%\Desktop
set /p FolderLoop="How many folders?: "
for /l %%x in (1, 1, %FolderLoop%) do (
set /p "folder=Folder: "
md "!folder!"
)
(the %%x after set /p does nothing. I removed it. I also removed it from md, you don't need it - except you want the counter be part of the foldername.)

Related

Batch File - Read specific line, and save a specific string in that line as a variable

Is there any way to get for /f loop (or anything else) to read a specific line?
Here is the code I have so far, it reads first word of every line.
#echo off
set file=readtest.txt
for /f "tokens=1 delims= " %%A in (%file%) do (echo %%A)
pause
If someone can point me in the right direction, it'd be much appreciated.
Thanks
Additional Information: I want to make a batch file which will rename a TXT file to a string within that TXT file, located at a specific location. I have figured out how to rename files, all I need to learn to do is to retrieve a string (located at a specific location) with in the file which will go into the name of that TXT file.
Since you haven't fully defined what you mean by "a specific location", I'll make some (reasonable, in my opinion) assumptions, though the method I present is equally valid no matter what your definition turns out to be.
You can get arbitrary lines and arbitrary words on that line by using a line counter variable in conjunction with tokens.
Let's assume your text file name can be found as the second argument on the fourth line of the infile.txt file. You can get that with something like:
#setlocal enableextensions enabledelayedexpansion
#echo off
set /a "line = 0"
for /f "tokens=2 delims= " %%a in (infile.txt) do (
set /a "line = line + 1"
if !line!==4 set thing=%%a
)
endlocal & set thing=%thing%
echo %thing%
This actually uses a few "tricks" which warrant further explanation:
the line counter to ensure you only grab what you want from a specific line, though you could change the test !line!==4 into anything you need such as a line beginning with #, the fifth line containing the string xyzzy and so on.
the use of setlocal/endlocal to effectively give you a scope from which variables cannot leak. This is good programming practice even for a language often not normally associated with such things :-)
the use of endlocal & set to bypass that scope so that thing is the only thing that does actually leak (as it should).
the use of delayed expansion and !..! variables to ensure they're correct within the for loop. Without this, the %..% will always be expand to the value they were set to when the for loop started.
Those last two bullet points are actually related. %..% variables are expanded when the command is read rather than when it is executed.
For a for loop, the command is the entire thing from the for to the final ). That means, if you use %line% within the loop, that will be evaluated before the loop starts running, which will result in it always being 0 (the variable itself may change but the expansion of it has already happened). However, !line! will be evaluated each time it is encountered within the loop so will have the correct value.
Similarly, while endlocal would normally clear out all variables created after the setlocal, the command:
endlocal & set thing=%thing%
is a single command in the context of expansion. The %thing% is expanded before endlocal is run, meaning it effectively becomes:
endlocal & set thing=whatever_thing_was_set_to_before_endlocal
That's why the use of setlocal and endlocal & set is a very useful way to limit variables "escaping" from a scope. And, yes, you can chain multiple & set stanzas to allow more variables to escape the scope.

Passing variable out of setlocal code

When writing scripts in Windows batch files, sometimes the proper execution of the script requires the use of the setlocal command. My main complaint about using setlocal is that I'm often performing complicated for & if statements in which I set variable values in that section of code. These settings are lost when I issue the command endlocal.
So far I've worked around this by echoing the variable value into a scratch file within the setlocal segment and then read the value back into the variable after the endlocal. However, it seems like there should be a more elegant solution to the problem.
The suggested answer provides a handy way to circumvent the issue if only using one or multiple set statements. However, the linked answer does not provide a solution when the setlocal is in place to allow a for loop to properly expand variable names at time of execution rather than parsing. In my situation, I also have if statement logic tree to perform further checking on that information to set many different possible variable values. The linked solution does not provide a solution to this situation.
This code is supposed to check an install package for its version number. It is called from another script that requires that version number to function correctly. We know the package is named using the form [application][version number].msi. The [version number] can be any of the following:
7
7.5
9
9.5
10
10.1
It is possible that more than one install package exists in the designated directory so it's important to look through them all and select the highest version in the directory.
I inherited and expanded the code to correctly process the 10 & 10.1 versions. If there's a better way to do this without the setlocal (e.g. I've thought of rewriting to use a case statement) I'd love to see a better solution.
However, I'm still interested in learning how to pass variables out of the setlocal / endlocal segment.
setlocal enabledelayedexpansion
for /f %%a in ('dir /b program*.MSI') do (
set FileName=%%a
set tst1=!FileName:~4,3!
if "!tst1!" == "msi" (
rem Only true if it has a 1 digit number (e.g. "9")
set MAIN_VERSION=!FileName:~2,1!
) else (
set tst2=!FileName:~5,3!
if "!tst2!" == "msi" (
rem Only true if it has a 2 digit version number (e.g. "10")
set MAIN_VERSION=!FileName:~2,2!
) else (
... lots more code ...
)
)
)
rem Write results out to a file for temporary storage. This particular
rem form of echo is required to ensure there are no trailing spaces, CR,
rem or LF
echo|set /P ="!MAIN_VERSION!" > %USERPROFILE%\UGV.txt
rem End local variables
endlocal
rem Read the correct version out of our temporary storage file
set /p MAIN_VERSION=<%USERPROFILE%\UGV.txt
How do I pass a variable (such as MAIN_VERSION above) out of a Windows batch script setlocal / endlocal code segment without using a scratch file?
To preserve variables over the setlocal/endlocal scope, there exists different solutions.
It depends of the situation which one you should use.
1) Simple
Works only outside of parenthesis blocks with simple content, but can produce problems with special characters like !^".
setlocal
set localVar=something simple
...
(
endlocal
set "out=%localVar%"
)
set out
2) Medium
Works also in blocks and can handle the most characters, but can fail with !^ and linefeed/carriage return
if 1==1 (
setlocal EnableDelayedExpansion
set "localVar=something medium nasty & "^&"
for /F "delims=" %%V in ("!localVar!") DO (
endlocal
set "out=%%V"
)
)
set out
3) Advanced
Works for all contents in any situation
SO: preserving exclamation marks in variable between setlocals batch

CMD program "for" loop error

echo off
set apk[0]=apk
for /r %%a in (.apk) do call array.bat add apk %%a
call array.bat len apk length
echo apk files found = %length%
for /l %%G in (1,1,%length%) do (
call array.bat getitem apk %%G item
echo %item%
)
echo Pick one:
set /p pick=
call array.bat getitem apk %pick% chose
echo.
echo You picked %chose%.
pause
In the above code i get length of apk array as 9 but the for loop prints ECHO is off 10 times?!
I am able to access to individual elements of the array o_O and also down the code after the user picks the choice it displays correctly. What am i doing wrong?
As a very quick fix, try
call echo %%item%%
This is generation 7,863 of delayedexpansion. There are hundreds of SO entries on this subject. Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
Note also that your item-displayed using your original code is the last item set in a prior run. You do not have a setlocal command in your batch, so the environment changes are established permanently, not backed out at the end of each batch. The consequence is that you are running with a contaminated environment.

ren won't use my variable from one lina above

I've got a strange problem. I want to rename multiple files in a folder.
So far, so easy - in theory. I use this script:
cd C:\Test
for %%i in (*(7*) do (
set name="%%i"
ren "%name%" "%name:~0,-15%.txt"
)
pause
The strange thing is that he seems to not use the variable "name" I declared
one line above the ren command as you can see in what the console prints:
C:\Test>(
set name="ttttt(7xAAdoc) .txt"
ren "" "~0,-15.txt"
)
What am I missing here? I am running Windows 7, if thats important.
Thanks for any help.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
In your case,
cd C:\Test
setlocal enabledelayedexpansion
for %%i in (*(7*) do (
set "name=%%i"
ren "%name%" "!name:~0,-15!.txt"
)
note the positioning of the quotes in the first set. The set "var=value" syntax ensures that any trailing spaces on the batch line are not included in the value assigned to var. As you had it, name would be assigned a "quoted" value and the ren command (had it worked) would have been `ren ""filename"" ""firstpartoffilename".txt"

How to combine number and string in batch file

I am using batch file to display some kind of number such as
00_test.txt 01_test.txt...10_test.txt 11_test.txt
Hence, This is my code. But I cannot show as my expectation
FOR /L %%x IN (1,1,10) DO (
set "extension=.txt"
set "fullname=%x%_test%extension%"
echo.%fullname%
)
The result of above code are _test.txt _test_txt but expected result are
00_test.txt 01_test.txt
Could you help me edit it?
#echo off
setlocal enabledelayedexpansion
set "baseName=_test"
set "extension=.txt"
for /l %%a in (1 1 10) do (
set "n=0%%a"
echo !n:~-2!%baseName%%extension%
)
When a block of code (in your case the for and the code inside parenthesis) is reached by the parser, all variable reads are replaced with the value in the variable before starting to execute the code. So, if a variable is changed inside the block and the value needs to be retrieved inside the same block, it is necessary to use delayed expansion, telling the parser that variables that are referenced as !var! (instead of %var%), should not be replaced at parse time, its value should be accessed at execution time.
So, in this code %baseName% and %extension% are used with usual syntax as its value does not change inside the for code block, but !n! uses delayed expansion. Its value changes inside the block and this value must be accessed inside the same block.
The concatenation of a 0 prefix and the extraction of two characters on the right from the variable ensure the presence of the initial 0 for values 1 to 9
Try %%x instead of %x:
FOR /L %%x IN (1,1,10) DO (
set "extension=.txt"
set "fullname=%%x%_test%extension%"
echo.%fullname%
)

Resources