How to loop an array in batch and move files - windows

I have the following:
#echo off
set Arr[0]=1234
set Arr[1]=2351
set Arr[2]=4321
set Arr[3]=6106
How can I loop in an array? Also at each loop I want to see if a file exists that contains like a wildcard the number of the Array. For example for Arr[0] if there's a file that contains 1234 like ABC_1234.txt or 1234_ABC.txt or 1234.txt then returns true otherwise false.
I'm a complete beginner in batch so any help appreciated.

Given your provided example variable value strings, I'd suggest this simple sort of approach. It parses the variable names defined within the environment, via the Set command.
#Echo Off
SetLocal EnableExtensions
Rem Ensure that there are no existing Arr[n] variables.
For /F "Delims==" %%G In ('2^> NUL Set Arr[') Do Set "%%G="
Rem Define new Arr[n] variables.
Set "Arr[0]=1234"
Set "Arr[1]=2351"
Set "Arr[2]=4321"
Set "Arr[3]=6106"
Rem Loop through the Arr[n] variables.
For /F "Tokens=1,* Delims==" %%G In ('2^> NUL Set Arr[') Do Echo "%%H"
Pause
I've just used Echo "%%H" in the loop, you'd obviously replace that with your If Exist, Dir etc. command to search for the files with respect to those variable value strings.

Related

Remove duplicates from comma separated list in batch file

I have a batch file that (among other things) turns a list like this:
'foo_ph1-1.tif', 'foo_ph2-1', 'foo_ph2-2'
into a list like this, in a local variable called INVNOS:
'fooph1', 'fooph2', 'fooph2'
I want to remove the duplicates from the second list. I've been trying to do this when I create the list, from the answers to this question, to no avail.
Here's how I make the list.
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%f in ("*.tif") do #echo %%~nf>>list.lst
set FNAMES=
set INVNOS=
for /f %%i in ('type list.lst') do (
set FNAMES=!FNAMES!'%%i.jpg',
for /f "tokens=1 delims=-" %%a in ("%%i") do (
set BEFORE_HYPHEN=%%a
set INVNOS=!INVNOS!'!BEFORE_HYPHEN:_=!',
)
)
set "FNAMES=%FNAMES:~0,-2%"
set "INVNOS=%INVNOS:~0,-2%"
echo %INVNOS%
endlocal
Solutions with findstr won't work because I need to initialize INVNOS with an empty string, and I get stuck with the difference between % and '!', and slicing, inside the for loop.
I know this is easy in Python, however I'd like to do it with what's native (Windows 10/Windows Server), so CMD or Powershell.
Any suggestions?
Just to sketch the bigger picture, INVNOS (inventory numbers) is derived from directories full of tif's, so we can check whether or not they exist in some sql database.
I would approach the problem differently:
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%f in (*.tif) do (
for /f "delims=-" %%g in ("%%~nf") do set "~%%g=."
)
for /f "delims=~=" %%a in ('set ~') do set "INVOS='%%a', !INVOS!"
set "INVOS=%INVOS:~0,-2%
echo %INVOS:_=%
The trick is to define variables for each filename (the variableNAMES contain the filenames. A variable can only exist once, so per definition, there are no duplicates)
With another for loop extract the names from the defined variables and join them. The underscores can be deleted in one go instead of removing them from each substring.
When needed, you can delete the variables with for /f "delims==" %%a in ('set ~') do set "%%a=", but they are destroyed anyway when the script ends. (same line when you want to be sure, no variable starting with ~ is defined by accident before you set them)
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:: The values assigned to these variables suit my system and test environment
SET "sourcedir=u:\your files"
SET "tempfile=%temp%\tempfile.txt"
:: remove variables starting :
FOR /F "delims==" %%a In ('set : 2^>Nul') DO SET "%%a="
(for %%f in ("%sourcedir%\*.tif") do echo %%~nf)>"%tempfile%"
set "FNAMES="
set "INVNOS="
for /f "usebackqdelims=" %%i in ("%tempfile%") do (
set FNAMES=!FNAMES!'%%i.jpg',
for /f "tokens=1 delims=-" %%a in ("%%i") do (
set "BEFORE_HYPHEN=%%a"
SET "before_hyphen=!BEFORE_HYPHEN:_=!"
IF NOT DEFINED :!BEFORE_HYPHEN! set "INVNOS=!INVNOS!'!BEFORE_HYPHEN:_=!', "&SET ":!BEFORE_HYPHEN!=Y"
)
)
set "FNAMES=%FNAMES:~0,-2%"
set "INVNOS=%INVNOS:~0,-2%"
echo %INVNOS%
IF DEFINED tempfile DEL "%tempfile%"
GOTO :EOF
You would need to change the value assigned to sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I deliberately include spaces in names to ensure that the spaces are processed correctly.
%tempfile% is used temporarily and is a filename of your choosing.
The usebackq option is only required because I chose to add quotes around the source filename.
it is standard practice on SO to use the syntax set "var=value" for string
assignments as this ensures stray trailing spaces on the line are ignored.
Evil trailing space on OP's code set INVNOS... within the for ... %%a loop.
Given OP's original filename list, foo_ph1-1.tif foo_ph2_1 foo_ph2-2, the processing should produce fooph1 fooph21 fooph2, not fooph1 fooph2 fooph2 as claimed.
My testing included foo_ph2-2.tif
The code is essentially the same, but first clearing any environment variables that start :, on the Irish principle.
The temporary file nominated is recreated avoiding the (unfulfilled) requirement to first delete it.
BEFORE_HYPHEN is explicitly expunged of underscores before the if not defined test is applied. I selected : because : can't be part of a filename. Once the name is applied to the invnos list, the :!BEFORE_HYPHEN! variable is established to prevent further accumulation of repeat BEFORE_HYPHEN values into invnos.
If you wanted to step up to PowerShell, something like this could be done in a .bat file script. Of course, It would be easier to write and maintain if it were all written in PowerShell.
=== doit.bat
#ECHO OFF
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
"(Get-ChildItem -File -Filter '*.tif' |" ^
"ForEach-Object { '''' + $($_.Name.Split('-')[0].Replace('_','')) + '''' } |" ^
"Sort-Object -Unique) -join ','"') DO (
SET "INVNOS=%%~A"
)
ECHO INVNOS is set to %INVNOS%
EXIT /B
Get-ChildItem produces a list of all the *.tif files in the directory. Split() does what "delims=-" does in a FOR loop. The [0] subscript chooses everything up to the first '-' character in the file name. Replace will remove the '_' characters. Sort-Object removed duplicates to produce a unique list. The -join converts the list of names to a single, comma delimited string. The resulting string is stored into the INVNOS variable.
Do you really want APOSTROPHE characters around each name in the list?

SET Command Doesn't Echo FOR /F Loop Parameter Values [duplicate]

This question already has answers here:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
(8 answers)
Closed 3 years ago.
I ran across an issue using the SET command inside a FOR /F loop to echo the values of the loop parameters (e.g., %%g, %%h, etc.). I used the SET command because I wanted to see what values get assigned to each FOR /F loop parameter when the FOR /F loop iterates. I am specifically looking to see how many caret escape characters (^) are stripped by the CMD parser as it processes the line of test code that is the last element in the $code_test[00] array record:
#echo off
setlocal disabledelayedexpansion
set $code_test[00]=Record [00],2,green,blue,if not exist ^^!$m^^!^^!$n^^! (set /a $result+=3)
echo Value using ECHO command:
echo $code_test[00] = %$code_test[00]%
echo.
echo Value using SET command with Delayed Expansion DISABLED:
set $code_test[
echo.
setlocal enabledelayedexpansion
echo Value using SET command with Delayed Expansion ENABLED:
set $code_test[
echo.
for /f "tokens=1-10 delims=," %%g in ('set $code_test[') do (
echo For /f loop values using ECHO command ...
echo g = %%g
echo h = %%h
echo i = %%i
echo j = %%j
echo k = %%k
echo.
echo For /f loop values using SET command ...
set %%g
set %%h
set %%i
set %%j
set %%k
)
The code populates one record for the $code_test[xx] array with various elements, the last of which is a Windows CMD test code statement. I want to see the value of the FOR /F loop parameter that corresponds to this test code statement, which is %%k. So, I used both the echo and set commands to echo the value of %%k to see if %%k retained the caret (^) escape characters that were present in the original test code definition for $code_test[00]. The echo command worked as expected and stripped the caret escape characters (^) from the code. But the set command completely failed. I've read the post about how the CMD interpreter parses code here and I didn't see an answer to my question.
I realize that dealing with FOR /F loop parameters can be tricky. Should I just assume that I can't deal with FOR /F loop parameters directly (e.g., set %%k) and make it a policy to always assign the value of a FOR /F parameter to an environment variable then deal with the environment variable instead of the FOR /F parameter?
SET "blue62=108"
SET "%%%%k=hello"
ECHO after SET %%%%%%%% k errorlevel=!errorlevel!
set|FIND "k="
echo For /f loop values using SET command ...
ECHO ++++++++++++++++!errorlevel!
set %%g
set %%h
set %%i
set %%j
ECHO :::::::::::::::::::::!errorlevel!
SET if not exist !$m!!$n! (set /a $result+=3)
ECHO -----------!errorlevel!-------------------
ECHO :::::::::::::::::::::!errorlevel!
SET "if not exist !$m!!$n! (set /a $result+=3)"
ECHO -----------!errorlevel!-------------------
set %%k
)
I expanded your reporting to include the above code with these results:
For /f loop values using ECHO command ...
g = $code_test[00]=Record [00]
h = 2
i = green
j = blue
k = if not exist !$m!!$n! (set /a $result+=3)
after SET %%%% k errorlevel=0
For /f loop values using SET command ...
++++++++++++++++1
Environment variable 2 not defined
Environment variable green not defined
blue62=108
:::::::::::::::::::::1
-----------1-------------------
:::::::::::::::::::::1
-----------1-------------------
Environment variable %k not defined
I believe this demonstrates that set simply acts strangely if confronted with an argument that is not a simple space-absent string with optional = for assignment.
What was really curious was that the Environment variable %k not defined did not appear with the original code.
I believe you're really expecting a 1970's vintage design to not only be bullet-proof but act in a consistent manner when supplied with unanticipated data. Just treat it like your grandma. Very capable, but easily confused.

How to search a text file for a specific part of a string (line) then insert it into a variable?

USING BATCH/BASH On Windows:
I'm wondering how to search a text file (.txt) line by line as each line is its own string, look for the location directory (e.g, C:...) which is part of this string. and just take out that specific part and store in a variable.
This is to be done for each line though.
Any help would be appreciated.
TestRecID TestUserID 5 2017-04-20 TestTAtRec No 2.560 No C:\Test1\Test3 Tester
TestRecID TestUserID 5 2017-04-20 TestTAtRec No 2.560 No C:\Test2\Test2 Tester
TestRecID TestUserID 5 2017-04-20 TestTAtRec No 2.560 No C:\Test3\Test1 Tester
Presume that the above are each row in the text file.
At each space in the line that is where the different columns would have been in the DB.
The Expected Result would be to have:
C:\Test1\Test3 --> Variable 1
C:\Test2\Test2 --> Variable 2
C:\Test3\Test1 --> Variable n
Stored in some variable.
I really can't overstate enough how much of a newb I am with Batch/Bash for Windows
Follow Up Question:
for /f "tokens=9 delims= " %%a in (%findfile%) do echo %%a
I want to then store the %%a in a variable_name
I thought it would be a case of:
for /f "tokens=9 delims= " %%a in (%findfile%) do echo %%a
set variable_name = %%a
But it is not working??
Was Answered but I got given out to for asking a question in an answer,
The Answer given:
for /f "tokens=9 delims= " %%b in (%findfile%) do set "location=%%b"
EDIT
Working Loop for taking unique variables (Thanks to #Stephen):
REM Get Locations from textfile:
for /f "skip=1 tokens=9 delims= " %%a in (%findfile%) do set "_%%a=yes"
REM Translate into proper variables:
set count = 0
for /f "tokens=1* delims==#" %%a in ('set _') do (
set /a count+=1
set _location[%count%]=%%a
)
set _location
This is the FFMPEG function I'm using but I now need it to take in each variable separately:
for %%i in (%_location%\*.mp4) do (if not exist "%%~ni\" MD "%%~ni"
ffmpeg -i "%%i" -vframes 1 -f image2 -start_number 0 "%%~ni\%%~ni_Summary_%%3d.jpeg"
)
The %_location% part in the function above is where my issue is? of it not taking multiple variables at once
As it makes no sense to store the whole output into one variable, I assume, you want one variable for each of the lines.
#echo off
setlocal EnableDelayedExpansion
set n=0
for /f "tokens=9" %%a in (file.txt) do (
set /a n+=1
set _Var[!n!]=%%a
)
set _Var[
Note the parantheses after do. This is called a code block and is parsed and executed like a single command. (this is why you need delayed expansion).
EDIT to remove duplicates, you can either use a lot of code to compare the (maybe) new data with each of the already existing variables or use a strange trick: use the data as variable names (and some dummy string as value), so each duplicate will just "overwrite" an already existing variable and in a second step put the data (now variable names) as values into variables.
#echo off
SetLocal EnableDelayedExpansion
REM clear variables:
for /f "delims==" %%a in ('set _') do set "%%a="
REM get locations from textfile:
for /f "tokens=9" %%a in (file.txt) do set "_%%a=yes"
REM translate into proper variables:
set count=0
echo on
for /f "tokens=1* delims==#" %%a in ('set _') do (
set /a count+=1
set x=%%a
set _var[!count!]=!x:~1!
)
set _var
Note: your data shouldn't contain exclamation marks (!) due to delayed expansion.

Store Multiline String in Batch Variable

I need to remove a string that may occur inside a file. The string has many lines. Can I perform this action using a Batch script?
I've heard that you cant have variables with more than one line in Batch? The string will come from another file that I will read into a variable using Batch.
The following code seems to only store the 1st/last line of a file in the string?? Whats going wrong?
Rem Read file and store all contents in string
Set replace=
Set target=
Set OUTFILE=res.txt
for /f "delims=" %%i in (myFile.txt) do set target=%target% %%i
echo %target%
Rem When I print target I only have one line not many lines?? Whats going wrong
Rem Remove the target string from myOtherFile.txt: this code is from http://stackoverflow.com/questions/5273937/how-to-replace-substrings-in-windows-batch-file
for /f "tokens=1,* delims=ΒΆ" %%A in ( '"type myOtherFile.txt"') do (
SET string=%%A
SET modified=!string:%target%=%replace%!
echo !modified! >> %OUTFILE%
)
Try this:
#echo off &setlocal enabledelayedexpansion
for /f "delims=" %%i in (myFile.txt) do set "target=!target! %%i"
echo %target%
Inside a code block you need always delayed expansion for variables with variable values.
Try this, change last to:
echo !target!

How to read from a .properties file using batch script

I have a requirement where i'd like to read values from a .properties file
my properties file test.properties content
file=jaguar8
extension=txt
path=c:\Program Files\AC
From the above file I need to fetch jaguar or anything after =
Please help me. Thanks
For /F "tokens=1* delims==" %%A IN (test.properties) DO (
IF "%%A"=="file" set file=%%B
)
echo "%file%"
hope this could help
#echo off
FOR /F "tokens=1,2 delims==" %%G IN (test.properties) DO (set %%G=%%H)
echo %file%
echo %extension%
echo %path%
Note that there is no space after %%H. Else this causes a space to be appended, to file paths for example, and will cause file not found errors when the variables from the property files are used as part of a file path.Struggled for hours because of this!
A solution with support for comments (# style). See comments in code for explanation.
test.properties:
# some comment with = char, empty line below
#invalid.property=1
some.property=2
some.property=3
# not sure if this is supported by .properties syntax
text=asd=f
properties-read.bat:
#echo off
rem eol stops comments from being parsed
rem otherwise split lines at the = char into two tokens
for /F "eol=# delims== tokens=1,*" %%a in (test.properties) do (
rem proper lines have both a and b set
rem if okay, assign property to some kind of namespace
rem so some.property becomes test.some.property in batch-land
if NOT "%%a"=="" if NOT "%%b"=="" set test.%%a=%%b
)
rem debug namespace test.
set test.
rem do something useful with your vars
rem cleanup namespace test.
rem nul redirection stops error output if no test. var is set
for /F "tokens=1 delims==" %%v in ('set test. 2^>nul') do (
set %%v=
)
output from set test. (see above):
test.some.property=3
test.text=asd=f
The most important parts are:
the for-loop with the eol and delims option and
the if-checks that both variables %%a and %%b are set.
What you do in the for-loop with the variable and its value is certainly up to you - assigning to some prefixed variables was just an example. The namespacing approach avoids that any other global variable gets overridden.
For example if you have something like appdata defined in your .properties file.
I'm using this to get rid of an extra config.bat and instead using one .properties file for both the java app and some support batch files.
Works for me, but certainly not every edge case is covered here, so improvements welcome!
Try this
echo off
setlocal
FOR /F "tokens=3,* delims=.=" %%G IN (test.properties) DO ( set %%G=%%H )
rem now use below vars
if "%%G"=="file"
set lfile=%%H
if "%%G"=="path"
set lpath=%%H
if "%%G"=="extension"
set lextention=%%H
echo %path%
endlocal
I know this is ancient post but I would like to expand on toschug's great answer.
If the path in the .properties file would be defined as %~dp0 or any other variable that needs to be expanded first before using it, I recommend doing it the following way:
In the .properties file:
path=%~dp0
In the batch file you can then use it the following way (the code is to be used between the two for(s) defining one <=> cleanup one):
if "!test.path!" NEQ "" (
echo Not expanded path: !test.path!
call :expand !test.path! test.path
)
echo test.path expanded: !test.path!
pause
:expand
SET "%~2=%~1"
GOTO :EOF
Don't forget to use (at the start of the batch file):
SETLOCAL ENABLEDELAYEDEXPANSION
you can try this:
#ECHO OFF
#SETLOCAL
FOR /F "tokens=1* delims==" %%A IN (test.properties) DO (
ECHO %%A = %%B
)
#ENDLOCAL

Resources