How to open a series of folders numbered 01-18 - batch-file

I was trying to open a folder on every lab computer using a batch script. The computers are labeled 01,02,03-18. I didn't think there was a way to convert the number from 1 to 01 so I used an if statement. But I am getting an error that says 9 was unexpected at this time
#echo off
setlocal enabledelayedexpansion
SET "z=0"
SET "n=9"
for /L %%x in (1,1,18) do (
SET v=%%x
IF %v% LEQ %n%
(
SET num=%z%%v%
) ELSE (
SET num=%v%
)
start "" "\\lab-!num!\
pause
)

You have problems with the placement of th parenthesis (see here), and an inconsistent usage of the delayed expansion (you are using !num! but not !v!, the two variables that change inside the code block) but the code can be simplified by including the padding in the values of the for loop
for /l %%x in (1001, 1, 1018) do (
set "num=%%x"
start "" "\\lab-!num:~-2!\share\folder"
)

When delayed expansion is enabled, use exclamation marks inside for loops.
And don't forget that open parenthesis must be on the same line as the if
#echo off
setlocal enabledelayedexpansion
SET "z=0"
SET "n=9"
for /L %%x in (1,1,3) do (
SET v=%%x
IF !v! LEQ !n! (
SET num=!z!!v!
) ELSE (
SET num=!v!
)
start \\lab-!num!\
pause
)

Related

Unable to get the desired result or output while using if-else statement inside a For loop of a batch script

I am stuck at below batch script for couple of days. Am not able to get my expected output. My if-else statement is not working as I expect. I want it to do certain actions when it encounters "----" and move to else statement otherwise. My output is always executing one else statement every single time.
else (
ECHO(!arga!,"","",!argd!,!arge!,!argf!,!argg!,!argh!)>>myFile.csv
)
Either the value of variable is not getting updated or there is some issue with my logic.
I am a beginner to batch scripting, I wrote the if-else statements based on C/Java/Python programming knowledge. I am confused whether I should go for GOTO labels to perform my desired function.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
del "C:\Program Files\report.txt"
del myFile.csv
del test1.csv
call "C:\Program Files\report.bat" >> "C:\Program Files\report.txt"
setlocal enabledelayedexpansion
FOR /F "skip=3 usebackqtokens=1-7*delims= " %%a in (report.txt) do (
set "arga=%%a"
set "argb=%%b"
set "argc=%%c"
set "argd=%%d"
set "arge=%%e"
set "argf=%%f"
set "argg=%%g"
set "argh=%%h"
if !argb! equ [-----] (
if !argd! equ [-----] (
ECHO(!arga!,"","","","",!argf!,!argg!,!argh!)>>myFile.csv
) else (
ECHO(!arga!,"","",!argd!,!arge!,!argf!,!argg!,!argh!)>>myFile.csv
)
) else (
if !argd! equ [-----] (
ECHO(!arga!,!argb!,!argc!,"","",!argf!,!argg!,!argh!)>>myFile.csv
) else (
ECHO(!arga!,!argb!,!argc!,!argd!,!arge!,!argf!,!argg!,!argh!)>>myFile.csv
)
)
)
del newMyFile.CSV
echo jobName,lastStartdate,lastStartTime,lastEndDate,lastEndTime,status,runPri,exit > newMyFile.CSV
type myFile.csv >> newMyFile.CSV
for /f "usebackq tokens=* delims=," %%a in ("newMyFile.CSV") do (
ECHO %%a
)
As well as all of the advice already provided in the comments, you don't need to set any variables, or use delayed expansion. Additionally you don't need to pre-delete any files if you use the redirection operator >, and you also should not need to create report.txt, or myFile.csv either. Finally, you don't need a for /f loop to view your new file, you can just use type. I'd expect that the following batch file example would perform the same task, much more simply, and quicker too!
This rewrite assumes that you don't really intend to create your CSV file in Program Files, which would require your script to be 'Run as administrator', but in the current directory instead.
#Echo Off
SetLocal DisableDelayedExpansion
( Echo jobName,lastStartdate,lastStartTime,lastEndDate,lastEndTime,status,runPri,exit
For /F "Skip=3 Tokens=1-7,*" %%G In ('"C:\Program Files\report.bat"'
) Do If "%%H" == "[-----]" (If "%%J" == "[-----]" (
Echo %%G,"","","","",%%L,%%M,%%N
) Else Echo %%G,"","",%%J,%%K,%%L,%%M,%%N) Else If "%%I" == "[-----]" (
Echo %%G,%%H,%%I,"","",%%L,%%M,%%N
) Else Echo %%G,%%H,%%I,%%J,%%K,%%L,%%M,%%N
) 1> "newMyFile.CSV"
Type "newMyFile.CSV"
Pause

Batch: using upper for loop parameter in lower one

The command im trying to run is:
::%items% is defined elsewhere and is the amount of items per line in the file
FOR /F "usebackq tokens=1-%items% delims=," %%1 IN (`TYPE %TextFile%`) DO (
FOR /l %%a in (%items%,-1,1) do (
set /a "number=%%a"
echo !number!
:: This is the main command I believe im having issues with
set word!number!=%%!number!
echo !word1!
echo !word2!
echo !word3!
)
set /a "lineused%randomline%=1"
goto exitloop
)
:exitloop
pause
Now what I'm trying to do is set the variable called wordX where X is the number of the token. Edit: Basically, trying to use the %% variabla from the upper for loop which the lower one is running inside of.
I could type all the lines of
set word1=%%1
set word2=%%2
set word3=%%3
but that would defeat the purpose of the versatile system I'm trying to build.
Format of the text file (%TextFile%) would simply be, in this case:
line1i1,line1i2
line2i1,line2i2
But I need for it to work also on for example:
line1i1,line1i2,line1i3,line1i4
line2i1,line2i2,line2i3,line1i4
Interesting idea, but that cannot work because FOR variable expansion takes place before delayed expansion. You need a method to get an extra round of FOR variable expansion.
You can CALL a subroutine, and then use a dummy FOR loop to re-establish a FOR context. FOR variables are global in scope as long as you are in a FOR loop context. So your subroutine can access a FOR variable that was defined earlier.
...
...
FOR /F "tokens=1-%items% delims=," %%1 IN ('TYPE %TextFile%') DO (
FOR /l %%a in (%items%,-1,1) do call :set %%a
echo !word1!
echo !word2!
echo !word3!
)
...
...
exit /b
:set
for %%. in (.) do set "word%1=%%%1"
exit /b
The above works, but I don't like it because CALLs are expensive (slow). This is typically not a problem when you only have a few CALLs. But in this case the CALL is in a tight loop - one for every column times the number of rows in the file. Ouch!
If you really want to parametize your SET statements, and you want decent performance, then you can define a dynamic "macro". Simply store the needed commands in a variable, and then execute the content of the variable within your loop.
Also note that the above is limited to 9 items (10 if you start with 0 instead of 1). It is easy to extend the supported item count to 26 if you use letters, and a lookup string.
Finally, your dynamic FOR is within some parenthesized block. Presumably your ITEMS is defined outside the block, otherwise %items% could not be used in the FOR /F definition. The SET macro must be expanded using regular expansion, so it should be defined at the same time ITEMS is defined - outside the outer loop.
set /a items=3
::Define SET macro
set "v= ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "set="
for /l %%N in (1 1 %items%) do set "set=!set!&set "word%%N=%%!v:~%%N,1!""
set "set=!set:~1!"
FOR ... some loop ... DO (
...
...
FOR /F "tokens=1-%items% delims=," %%A IN ('TYPE %TextFile%') DO (
%set%
echo !word1!
echo !word2!
echo !word3!
)
...
...
)
If the ITEMS variable must be set within the outer loop, then you must CALL out of the loop to establish the inner FOR /F loop.
Note that you dont need the TYPE to get contents of file, the FOR command itself can iterate over file content
You could try something like this:
#echo off
setlocal enabledelayedexpansion
set "TextFile=textfile.txt"
set /a "lineNum=0"
set /a "i=0"
for /f "tokens=*" %%a in (%TextFile%) do (
set /a lineNum=!line_num! + 1
set "line=%%a"
for %%b in ("!line:,=" "!") do (
set /a "i=!i!+1"
set /a "wordNum=!lineNum! * !i!
set "word!wordNum!=%%b"
)
)
echo !word1!
echo !word2!
echo !word3!
Given a file with the contents:
aaa,bbb,ccc,ddd
eee,fff,ggg,hhh
Output will be:
"aaa"
"bbb"
... and so on
To remove the quotes, use %%~b at the inner FOR at set "word!wordNum! line.
Also note that you don't even need to define the number of items per line!
Hope it helps,
Cheers!

Trying to reformat a very large csv with a batch file

I have an application that exports data in the format:
1a,1b,1c1,1c2,1c3, ... (up to 1c100),1d1,1d2,1d3, ... (up to 1d100)
2a,2b,2c1,2c2,2c3, ... (up to 2c100),2d1,2d2,2d3, ... (up to 2d100)
etc.
and I am trying to reformat this into
1a,1b,1c1,1d1
1a,1b,1c2,1d2
.
.
1a,1b,1c100,1d100
2a,2b,2c1,2d1
2a,2b,2c2,2d2
etc.
I figured that if this can be done a row at a time I can just loop through the file. However I can't find a way of doing a single row with either tokens, a list, or even as a string function. There is too much data to process in a single operation (each value is about 12 chars). Tokens limit at (roughly) 64/202, a list at about 107/202 and a string at about 1000/2300
Does anyone know how this can be written into a new file?
I was trying things like:
#echo off
setlocal enableDelayedExpansion
set dimCnt=0
<example.csv (
set /p "dimList=" >nul
for %%D in (!dimList!) do (
set /a dimCnt+=1
set "dim[!dimCnt!]=%%D"
)
)
echo
for /l %%I in (3 1 102) do echo !dim[1]!,!dim[2]!,!dim[%%I]!
</code>
..besides the fact that I have missed out the last variable in the line (need to add 100 to it), I can't get more than about 80-110 values out of the list (I guess it depends on value string length)
#echo off
setlocal enableextensions enabledelayedexpansion
(for /f "tokens=1,2,* delims=," %%a in (example.csv) do (
set "data=%%c"
set "i=0"
for %%f in ("!data:,=" "!") do (
set /a "i+=1"
set "d[!i!]=%%~f"
)
set /a "end=!i!/2"
set /a "j=!end!+1"
for /l %%i in (1 1 !end!) do (
for %%j in (!j!) do echo %%a,%%b,!d[%%i]!,!d[%%j]!
set /a "j+=1"
)
)) > output.csv
endlocal
This iterates over the file, getting the first two tokens in the line (%%a and %%b), the rest of the line (%%c) is splitted and each value stored in an environment variable array (kind of). Then, the array is iterated from the start and from the middle, reading the needed values to append to %%a and %%b and generating output file.
#ECHO OFF
SETLOCAL
(
FOR /f "tokens=1,2,*delims=," %%a IN (u:\long.csv) DO (
SET rpta=%%a
SET rptb=%%b
CALL :rptcd %%c
)
)>newfile.txt
GOTO :EOF
:rptcd
SET /a lines=100
SET lined=%*
FOR /l %%x IN (1,1,99) DO CALL SET lined=%%lined:*,=%%
:loop
IF %lines%==0 GOTO :EOF
SET /a lines-=1
CALL SET lined=%lined:*,=%
FOR /f "delims=," %%x IN ("%lined%") DO ECHO %rpta%,%rptb%,%1,%%x&shift&GOTO loop
GOTO :eof
This should get you going - just need to change the input filename and output filename...
Your code does not work because SET /P cannot read more than 1023 bytes. At that point it returns the data read so far, and the next SET /P picks up where it left off. Adapting your code to compensate will be very difficult. You would be better off using FOR /F as in MC ND's answer. But beware, batch has a hard limit of 8191 characters per line in pretty much all contexts.
Better yet, you could use another scripting language like JScript, VBS, or PowerShell. Performance will be much better, and the code much more robust and far less arcane. I love working with batch, but it simply is not a good text processing language.

Batch - Read contents of a file in an array

I've a text file with two rows (say param.txt) which is shown below:
Mar2012
dim1,dim2,dim3,dim4
I want to read this file in batch and store the contents of first line in a variable called cube_name. When I'm reading the second line, I want to split the comma delimited string dim1,dim2,dim3,dim4 and create an array of four elements. I am planning to use the variable and the array in later part of the script.
The code which I created is shown below. The code is not working as expected.
#echo off & setlocal enableextensions enabledelayedexpansion
set /a count_=0
for /f "tokens=*" %%a in ('type param.txt') do (
set /a count_+=1
set my_arr[!count_!]=%%a
)
set /a count=0
for %%i in (%my_arr%) do (
set /a count+=1
if !count! EQU 1 (
set cube_name=%%i
)
if !count! GTR 1 (
set dim_arr=%%i:#=,%
)
)
for %%i in (%dim_arr%) do (
echo %%i
)
echo !cube_name!
I get to see the following when I run the code:
C:\Working folder>test2.bat
ECHO is off.
So this doesn't appear to work and I can't figure out what I'm doing wrong. I am fairly new to the batch scripting so help is appreciated
Your first FOR loop is OK. It is not how I would do it, but it works. Everything after that is a mess. It looks like you think arrays are a formal concept in batch, when they are not. It is possible to work with variables in a way that looks reminiscent of arrays. But true arrays do not exist within batch.
You use %my_arr% as if it is an array, but my_arr is not even defined. You have defined variables my_arr[1] amd my_arr[2] - the brackets and number are part of the variable name.
It also looks like you have a misunderstanding of FOR loops. I suggest you carefully read the FOR documentation (type HELP FOR from a command line). Also look at examples on this and other sites. The FOR command is very complicated because it has many variations that look similar to the untrained eye, yet have profoundly different behaviors. One excellent resource to help your understanding is http://judago.webs.com/batchforloops.htm
Assuming the file always has exactly 2 lines, I would solve your problem like so
#echo off
setlocal enableDelayedExpansion
set dimCnt=0
<param.txt (
set /p "cube_name=" >nul
set /p "dimList=" >nul
for %%D in (!dimList!) do (
set /a dimCnt+=1
set "dim[!dimCnt!]=%%D"
)
)
echo cube_name=!cube_name!
for /l %%I in (1 1 !dimCnt!) do echo dim[%%I]=!dim[%%I]!
One nice feature of the above solution is it allows for a varying number of terms in the list of dimensions in the 2nd line. It will fail if there are tabs, spaces, semicolon, equal, * or ? in the dimension names. There are relatively simple ways to get around this limitation if need be.
Tabs, spaces, semicolon and equal can be handled by using search and replace to enclose each term in quotes.
for %%D in ("!dimList:,=","!") do (
set /a dimCnt+=1
set "dim[!dimCnt!]=%%~D"
)
I won't post the full solution here since it is not likely to be needed. But handling * and/or ? would require replacing the commas with a new-line character and switching to a FOR /F statement.
I'm impressed of your code!
Do you try to debug or echo anything there?
You could simply add some echo's to see why your code can't work.
#echo off & setlocal enableextensions enabledelayedexpansion
set /a count_=0
for /f "tokens=*" %%a in ('type param.txt') do (
set /a count_+=1
set my_arr[!count_!]=%%a
)
echo ### show the variable(s) beginning with my_arr...
set my_arr
echo Part 2----
set /a count=0
echo The value of my_arr is "%my_arr%"
for %%i in (%my_arr%) do (
set /a count+=1
echo ## Count=!count!, content is %%i
if !count! EQU 1 (
set cube_name=%%i
)
if !count! GTR 1 (
echo ## Setting dim_arr to "%%i:#=,%"
set dim_arr=%%i:#=,%
echo
)
)
for %%i in (%dim_arr%) do (
echo the value of dim_arr is "%%i"
)
echo cube_name is "!cube_name!"
Output is
### show the variable(s) beginning with my_arr...
my_arr[1]=Mar2012
my_arr[2]=dim1,dim2,dim3,dim4
Part 2----
The value of my_arr is ""
cube_name is ""
As you can see your part2 fails completly.

Unable to concatenate strings separated by comma

I'm being driven crazy by a stupidly simple problem that is eating up my time. I just want to append strings separated by comma, but the comma doesn't get appended. Below is my batch file snippet:
set MissingParams=
set SwitchURL=
set TrustStore=
if 0%SwitchURL%==0 (set MissingParams=SwitchURL)
if 0%TrustStore%==0 (
if not 0%MissingParams%==0 (
set MissingParams=%MissingParams%,
)
set MissingParams=%MissingParams%TrustStore
)
After runnin this script when I echo %MisingParams%, the expected value is SwitchURL,TrustStore but it simply prints
SwitchURLTrustStore.
D:\deleteme>echo %MissingParams%
SwitchURLTrustStore
For debugging, when I introduced some echo statements in the batch file, the results are even more bizzare:
set MissingParams=
if 0%SwitchURL%==0 (set MissingParams=SwitchURL)
if 0%TrustStore%==0 (
if not 0%MissingParams%==0 (
echo MissingParams=%MissingParams%
set MissingParams=%MissingParams%,
echo MissingParams=%MissingParams%
)
set MissingParams=%MissingParams%TrustStore
echo MissingParams=%MissingParams%
)
When I run the above script it prints
MissingParams=SwitchURL
MissingParams=SwitchURL
MissingParams=SwitchURL
And when I echo the value from the command prompt, as before I get SwitchURLTrustStore
D:\deleteme>echo %MissingParams%
SwitchURLTrustStore
Does anyone have any ideas? This is frustrating me to no end.
This is the standard parenthesis/delayedExpansion problem.
The simple rule is %var% are expanded before a parenthesis block is executed(while parsing).
If you need the var-expansion later, you should use the delayed expansion.
Explained in set /?
setlocal EnableDelayedExpansion
set MissingParams=
set SwitchURL=
set TrustStore=
if 0!SwitchURL!==0 (set MissingParams=SwitchURL)
if 0!TrustStore!==0 (
if not 0!MissingParams!==0 (
set MissingParams=!MissingParams!,
)
set MissingParams=!MissingParams!TrustStore
)
Sort of looks like a scoping problem. I was able to work around this by branching with a goto which works. Here's my version with extra debug crap:
#echo off
set MissingParams=
set SwitchURL=
set TrustStore=
if "%SwitchURL%"=="" (set MissingParams=SwitchURL)
echo MissingParams1 is %MissingParams%
if "%TrustStore%" EQU "" (GOTO :BRANCH1)
:RESUME
echo MissingParams3 is %MissingParams%
set MissingParams=%MissingParams%TrustStore
echo MissingParams4 is %MissingParams%
)
echo MissingParamsF is %MissingParams%
GOTO :eof
:BRANCH1
if "%MissingParams%" NEQ "" (set MissingParams=%MissingParams%,)
GOTO RESUME

Resources