CMD/Batch extract each text file line and loop from variable - loops

I have this code
#Echo Off
SetLocal EnableDelayedExpansion
SET mydir=D:\
SET DirCount=2
SET T=
For /F %%i In (qqq.txt) Do (
set fg=%%i
FOR /L %%G IN (2, 1, %DirCount%) DO (call :subroutine "%%i")
)
:subroutine
Set T=!T!../
start /wait %mydir%program.exe %T%%fg%
echo %t%%fg% >>%cd%see.log
qqq.txt has rows
1
2
3
In result i get:
../1
../../2
../../../3
../../../../3
But I need like this:
../1
../../1
../2
../../2
../3
../../3
Please Help what I'm doing wrong?
Just a little additional requried
I need what first ocur in
set "T=!T!../"
will be without dots
set "T=!T!/"
result must be
/1
../1
../../1
/2
../2
../../2
how and where to add counter and make visible for each loop somthing like
echo Now looping: %%i row of %countrow(in qqq.txt), left %countrow-%%I
echo Now looping: Dir Nr%%G !T!%%i
Sorry for stupid questions but batch coding is difficult to me.

You have 3 problems:
1) You don't exit your program after the main loop so it falls through into the subroutine
2) Your FOR /L IN() clause is wrong, the first number should be 1, not 2
3) You need to reset T back to undefined within the outer loop.
EDIT
I believe you may have an additional problem. When redirecting output you prefix your file name with %cd%. I don't think that is giving the result you want. If your current directory is C:\test, then >>%cd%see.log will result in output sent to file named testsee.log in the root C:\ directory. If you wanted the output in the current directory then it should be >>%cd%\see.log, but the path info is not really needed since the default is to use the current directory. So really all you would need is >>see.log. Since I don't know your intent, I have left the redirection as originally written. End Edit
#echo Off
SetLocal EnableDelayedExpansion
SET mydir=D:\
SET DirCount=2
For /F %%i In (qqq.txt) Do (
SET T=
set fg=%%i
FOR /L %%G IN (1, 1, %DirCount%) DO (call :subroutine "%%i")
)
exit /b
:subroutine
Set T=!T!../
start /wait %mydir%program.exe %T%%fg%
echo %t%%fg% >>%cd%see.log
There is no need to call a subroutine in your case, especially since you have already enabled delayed expansion. The following gives the same result with less code, and it is faster because it avoids the relatively slow CALL statement. (performance is probably not an issue in this small example, but if using loops with many iterations it can make a huge difference)
#echo Off
SetLocal EnableDelayedExpansion
SET mydir=D:\
SET DirCount=2
For /F %%i In (qqq.txt) Do (
SET "T="
FOR /L %%G IN (1, 1, %DirCount%) DO (
set "T=!T!../"
start /wait %mydir%program.exe !T!%%i
echo !T!%%i >>%cd%see.log
)
)
Partial answer to additional questions
You can use FOR /F to capture the result of FIND /C to get the number of lines in "qqq.txt". This should be done before you enter the main loop:
for /f %%N in ('find /c /v "" ^<qqq.txt') do set "rowCount=%%N"
You can use SET /A to do basic math, thus enabling you to keep track of the number of remaining lines
First initialize the remaining count before entering the main loop:
set "remainingLines=%rowCount%"
Then within the main loop use SET /A to decrement the value.
set /a remainingLines-=1

Related

Increment a variable already incremented in another loop

I would like to automate the execution of several commands to retrieve files from pods, with oc client.
I succeeded in incrementing the name of my variables, but I can't increment them in another loop to get their content.
#echo off
set /p "nbPod=How many times should RSYNC be used?? "
set num=0
for /l %%p in (1, 1, %nbPod%) do (
set /a "num = num + 1"
setlocal EnableDelayedExpansion
set /p "podName!num!= Enter pod name for pod number %%p ? "
)
set /a iteration=1
:loop
if %iteration% leq %num% (
setlocal EnableDelayedExpansion
echo %podName!iteration!%
::oc rsync %podName!iteration!%:/my_command_0
::oc rsync %podName!iteration!%:/my_command_1 [etc]
set /a "iteration = iteration + 1"
goto :loop
)
NB : I don't know why but set /a num+=1 wasn't working.
#ECHO OFF
SETLOCAL EnableDelayedExpansion
:: remove variables starting podname
FOR /F "delims==" %%b In ('set podname 2^>Nul') DO SET "%%b="
set /p "nbPod=How many times should RSYNC be used?? "
for /l %%p in (1, 1, %nbPod%) do set /p "podName%%p= Enter pod name for pod number %%p ? "
for /l %%p in (1, 1, %nbPod%) do (
echo !podName%%p!
rem within a block, use REM, not :: as :: is a broken label which terminates the block
rem oc rsync !podName%%p!:/my_command_0
rem oc rsync !podName%%p!:/my_command_1 [etc]
)
GOTO :EOF
Always verify against a test directory before applying to real data.
A few little issues with your code.
setlocal makes a copy of the current environment and processing continues using that new environment. An endlocal statement disposes of the new environment and restores the original. Reaching physical end-of-file is an implicit endlocal.
Consequently, it's normal to follow the initial #echo off with a setlocal as any statements executed before the setlocal are retained in the environment after the batch ends, which can cause confusion for subsequent batches as the variables use may be unexpectedly set.
There is a limit to the number of nested open setlocals that can be used (about 300). Unlikely to be a problem in this case, but something to note.
nbpod is your limit, so there's no requirement to use num or iteration.
I've no idea what the comments in the final loop are, but they MUST be rem statements within a block (parenthesised sequence of commands). OK- probably they are commented-out what I'm actually doing lines....
The for /f ... %%b command will process the list generated by set command, which would be something like
podname1=one
podname2=two
The delims= option causes for/f to assign the (default) first "token" in the line (podname1,podname2) to %%b and "sets" the value to nothing, deleting any stray variables from the environment. The 2^>nul suppresses error messages if there are no current variables named podname....
Then input the names as podname1... according to %%p.
And read them back using delayedexpansion, the current value of [podname strung with %%p]

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.

How do you keep input and design in the same line without it cutting out to the next line?

So i'm creating a batch file, that displays your directory and thats just one feature but anyways, you'll directory is going to change while in the batch file, and the therefore the directory text is going to change...
So here's an example of what it does...
|----------------------------------|
|>>C:\Users\Joel\..................|
|----------------------------------|
When you change your directory it looks like:
|----------------------------------|
|>> C:\Users\Joel\Desktop\.................|
|----------------------------------|
How do I make it so it takes how ever many letters than takes it away from the spaces?
Please help?
You want to pad a string to a fixed length. The simple strategy is to create a variable containing your string plus more than enough pad characters to reach your limit. Then use a substring operation to trim the string to the desired length. I modified the algorithm slightly to preserve the entire string if it is already greater than or equal to the desired length.
#echo off
:: Initialize
setlocal enableDelayedExpansion
set maxLen=50
set "pad="
set "div="
for /l %%N in (1 1 %maxLen%) do (
set "pad=!pad!."
set "div=!div!-"
)
set "div=|!div!|"
:: Test the display
pushd "c:\Users\Joel"
call :displayCurrentDirectory
pushd "c:\Users\Joel\Desktop"
call :displayCurrentDirectory
exit /b
:displayCurrentDirectory
setlocal
set "txt=>>!cd!\"
if "!txt:~%maxLen%,1!" equ "" (
set "txt=!txt!!pad!"
set "txt=!txt:~0,%maxLen%!"
)
echo !div!
echo ^|!txt!^|
echo !div!
echo(
exit /b
Here is a version that uses multiple lines of fixed width to force the string to fit within the alloted horizontal space.
#echo off
:: Initialize
setlocal enableDelayedExpansion
set maxLen=15
set "pad="
set "div="
for /l %%N in (1 1 %maxLen%) do (
set "pad=!pad!."
set "div=!div!-"
)
set "div=|!div!|"
:: Test the display
pushd "c:\Users\Joel"
call :displayCurrentDirectory
pushd "c:\Users\Joel\Desktop"
call :displayCurrentDirectory
exit /b
:displayCurrentDirectory
setlocal
echo !div!
set "txt=>>!cd!\"
:loop
if "!txt:~0,%maxLen%!" neq "!txt!" (
echo ^|!txt:~0,%maxLen%!^|
set "txt=!txt:~%maxLen%!"
goto :loop
)
set "txt=!txt!!pad!"
set "txt=!txt:~0,%maxLen%!"
echo ^|!txt!^|
echo !div!
echo(
exit /b
Take a look at Improved :Format, new :FormatVar and :FormatColor functions
for a more general purpose routine to format text. It allows left and right justification of text.

Command: for | It won't accept my variable in skip=%var% option

Well, I am kinda stuck on the following part of my code.
This program will count the number of lines in the file usernames_list.txt. On each line there is a name of a folder I want to enter. I want that program to enter each folder in my list, create a file called test_1 and then go to it's parent folder. This should be reapeated until it reaches the end of the list.
Am I doing it right? :/
For some reason the "skip" option won't accept my variable.
for /f %%C in ('Find /V /C "" ^< usernames_list.txt') do set lines=%%C
set times=0
set /A skip_value=%lines%-(%lines%-%times%)
:redo
FOR /F "skip=%skip_value%" %%b IN (usernames_list.txt) DO (
cd %%b
echo > test_1
cd ..
set /A times=%times%+1
if /i {%times%}=={%lines%} (goto continue)
goto redo
)
:continue
pause
As currently written, set /A skip_value=%lines%-(%lines%-%times%) will always evaluate to 0 because times = 0.
The SKIP value must be >= 1. Setting SKIP=0 results in a syntax error.
It seems to me your logic for computing skip_value is flawed. But even if you fix the logic, you still have to worry about values that are <= 0. I handle that situation by defining a SKIP variable with the entire option text only if the value is >= 1.
set "skip="
if %skip_value% geq 1 set "skip=skip=%skip_value%"
for /f "%skip%" %%b in (usernames_list.txt) ...
You might need additional FOR /F options. That is not a problem. For example:
for /f "%skip% delims=" ...

Reading file names and

I would like to create a batch-file that reads the first 10 file names in a spefic directory, and then sets the paths to 10 different variables. For a simple example, the path would be c:\test and inside there, there would be lots of files named file1.tif, file2.tif, etc. I would like to set the variable filepath1 equal to the path of the 1st file, which would be c:\test\file1.tif, and so on for the first 10 files. Here is the code:
#echo off
cd C:\TEST
setlocal ENABLEDELAYEDEXPANSION
FOR /f "delims=|" %%a IN ('dir /b') DO (
CALL SET /a x = !x! +1
if !x! == 1 (
CALL SET /a filepath!x!="C:\TEST\%%a"
)
)
echo %filepath1%
echo %filepath2%
pause
goto EOF
When I run the program, it seems to perform the FOR loop fine, but for filepath1 it displays just 0 and it does not display anything for filepath2. I belive the problem is in the if !X! == 1 and setting the filepath!x!. If I change anything to do with the !x!, it breaks the loop. What can I do to set the variables correctly and limit the loop to perform action on only 10 files?
I'm not quite sure if I got your question correct, because your orginal code contains some things that wouldn't make sense then (or are at least not necessary) :-)
the "delims=|" option you used is not doing anything in your case
when /a option is used for arithmetic (see help set) and is wrong when used with your set filepath!x!... line.
Anyway, the following should work:
setlocal ENABLEDELAYEDEXPANSION
cd C:\Test
FOR /f %%a IN ('dir /b') DO (
SET /a x = !x! +1
SET filepath!x!="C:\TEST\%%a"
if !x! equ 10 goto done
)
:done
rem filepath1 to filepath10 are defined now, given there were up to 10 matching
rem files in the first place.
echo %filepath1%
echo %filepath2%
pause
The code above does not do any error checking and does not verify that the files in question are actually called file1.tif to file10.tif. From your question (and sample code) it is not quite clear if that is really necessary in your case. You might want to clarify that, so that the above code can be improved regarding it.

Resources