Change a Variable in a For Loop in a Batch file - search

So I am trying to set multiple variables with a For Loop in a Batch file. I know I need to use EnableDelayedExpansion but I have tested out several different methods and so far nothing seems to work. Also, this will generally be run as a domain user that does not have a user folder on the computer.
The end goal is to collect the file path for notes.ini for each user directory. Originally I would repeat a section for each folder and change the variable to n1 then n2 then n3. I am trying to compact this and allow this file to handle any number of user folders. I need to be able to call each path individually latter int the batch file, so currently I have each path written to a txt file then the txt file parsed into a variable.
This is my original code:
SETLOCAL EnableDelayedExpansion
for /D %%x in ("C:\Users\*") do (
if exist %temp%\niresults.txt del /q %temp%\niresults.txt
dir "%%x\AppData\Local\lotus\Notes\*.*" /L /A /B /S|Find "notes.ini" >> %temp%\niresults.txt
If not exist %temp%\niresults.txt echo "Files not found"
set /p n1= < %temp%\niresults.txt
if exist C:\niresults.txt del /q C:\niresults.txt
)
I plan on using the variables in the following way.
wscript "FnR.vbs" "Find this" "Replace with this" !n1!
or
wscript "FnR.vbs" "Find this" "Replace with this" %n1% %n2% %n3%... etc
FnR.vbs is setup to accept and process parameters 3 through x in a loop so the number of parameters doesn't matter too much; however, FnR does take a little while to run. I thought about including the wscript "FnR.vbs" in the loop but currently I have to call it 4 times for each file location and will do that if I have to but it will slow everything way down.
So is there a way to get this to work so that each path will be in a different variable or change the name of the txt file for each time the loop is run? or omit the txt file and dump the output directly into a variable (I think this might be what I need most to get it to work with EnableDelayedExpansion)?
The easiest solution would be, is it possible to change n1 to n2 at the second iteration of the loop and n3 at the 3rd and so on.
I know I could back out and search a larger directory of C:\users for the files but with the amount of user data on most of the machines in my environment that would make the file take longer to run that the actions it would replace.

Alternatively to using 'indexed' variables, you could use a 'list' variable for collecting all the names in the loop and then just reference it later in the command line that calls the VB script. Something like this:
SETLOCAL EnableDelayedExpansion
set nlist=0
for /D %%x in ("C:\Users\*") do (
if exist %temp%\niresults.txt del /q %temp%\niresults.txt
dir "%%x\AppData\Local\lotus\Notes\*.*" /L /A /B /S|Find "notes.ini" >> %temp%\niresults.txt
If not exist %temp%\niresults.txt echo "Files not found"
set /p n1= < %temp%\niresults.txt
set nlist=!nlist! "!n1!"
if exist C:\niresults.txt del /q C:\niresults.txt
)
:: now all the names are in the %nlist% variable,
:: so you can call the VB script like this
wscript "FnR.vbs" "Find this" "Replace with this" %nlist%

You could take the approach used by Aacini in their answer to this question.
Here's how your script might look like with that approach:
SETLOCAL EnableDelayedExpansion
set i=0
for /D %%x in ("C:\Users\*") do (
if exist %temp%\niresults.txt del /q %temp%\niresults.txt
dir "%%x\AppData\Local\lotus\Notes\*.*" /L /A /B /S|Find "notes.ini" >> %temp%\niresults.txt
If not exist %temp%\niresults.txt echo "Files not found"
set /a i+=1
set /p n!i!= < %temp%\niresults.txt
if exist C:\niresults.txt del /q C:\niresults.txt
)
:: now that you've got an 'array' of n1, n2, n3 etc.
:: you can reference any or all of them as appropriate
wscript "FnR.vbs" "Find this" "Replace with this" "%n1%" "%n2%" "%n3%" ...

Related

Cannot set environmental variable inside a loop in a batch script

I have a batch script that works great and it does the following:
download EDI files from sftp server
generate a dynamic ftp scripts based on the filenames that were downloaded
uploads the file to an internal ftp server via FTP script
I need to modify the batch file to look at the content as some data coming in maybe missing a 0. I do have the logic on how to do this, however, I cannot add the logic to the loop I have as variables do not work.
Below is loop where I want to add the part to correct missing leading zero (that would be in position 4):
for /F "tokens=*" %%A in (c:\scripts\permitsin.txt) do (
echo put %%A /qsys.lib/MAEPFTDTA.lib/PERMITIN.file/%%A >> c:\scripts\ftp-to-scoopsoft.ftp1
)
What I need to do is add an environment variable which will be the content of the file and below is the sample code:
set /p string =< %%A
echo Value for string is set to %string%
echo %string:~9,1% | find "ECHO is on." > nul
if not errorlevel 1 goto Found0
echo no space found
goto End
:Found0
echo found space
echo below is what the correct number needs to be
echo %string:~0,3%0%string:~3% > %%A
:End
I need this to work in batch file as security requirements does not allow PowerShell on the servers.
for /F "tokens=*" %%A in (c:\scripts\permitsin.txt) do (
for /F "delims=" %%S in (%%A) do (
setlocal enabledelayedexpansion
set "string=%%S"
if "!string:~9,1!"==" " echo !string:~0,3!0!string:~3!> %%A
endlocal
)
echo put %%A /qsys.lib/MAEPFTDTA.lib/PERMITIN.file/%%A >> c:\scripts\ftp-to-scoopsoft.ftp1
)
should do what you appear to need. Test on sample data first, of course.
Here's the how : Stephan's DELAYEDEXPANSION link
And it saves a lot of work if you tell us what you want to do rather than how you want to do it.

Batch Move based on filename without Delimiters, String Only

Okay, Windows 7 Enterprise x64 here with a Windows batch file question. I am a somewhat basic user with little knowledge of batch file creation. I've modified existing scripts I've found online to my use, that is about it.
I have a piece of software that dumps it's output to a folder with file names concatenated from the project title, current system date, current system time, and project settings.
It will export two files in this format every time the project is saved:
PROJECTTITLE_2016_10_07__09_45_11__A_B_C.iges
PROJECTTITLE_2016_10_07__09_45_11__A_B_C.step
The A, B, and C representing switches used in the software that are specific to the project. These may exist or may not exist as in the file name can be _R_F or _R_F_Z etc.
"PROJECTTITLE" can literally be anything. This is where my problem arises using delimiters. You could potentially have file names like all of the following (using real examples from users):
11475shacklebody_2016_10_07__09_45_11__R_F.iges
11475shacklebody_2016_10_07__09_45_11__R_F.step
test_EFMflow_2016_10_07__09_45_11__R_Z.iges
test_EFMflow_2016_10_07__09_45_11__R_Z.step
untitled16_2016_10_07__09_45_11__R.iges
untitled16_2016_10_07__09_45_11__R.step
#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges
#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step
prooftestwithoutupperlandsimproved-4_2016_10_07__09_45_11.iges
prooftestwithoutupperlandsimproved-4_2016_10_07__09_45_11.step
What I want to do is move both the IGES and STEP files from the output folder on the C drive to a new folder on a networked drive with name based on "PROJECTTITLE," creating that folder if needed. I have already task scheduled a -delim based batch to run every night, but found delimiters to not be sufficient for my use.
While it seems like an easy job to do with delimiters, looking for the first underscore, I have had projects with underscores in their names that screws up the folder naming. Since delimiters only work for individual characters, not strings, I have been looking for examples of batch files I can adapt to my use with no luck finding any similar to what I want to do that do not use delimiters.
It seems simple, search for string "_2016," in filename, and take all characters before "_2016" and create a new directory, placing files containing those characters in that folder. I am lost as to how to do this without delimiters though.
What I have working so far, using delimiters looking for underscores, creating folders and moving to those folders on a mapped drive:
for /f "delims=_" %%V in ('dir /b /a-d C:\Output\*_*.iges') do (
mkdir "I:\ENG\PARTS\%%V" 2>nul
move "C:\Output\%%V_*.iges" "I:\ENG\PARTS\%%V" >NUL 2>nul
move "C:\Output\%%V_*.step" "I:\ENG\PARTS\%%V" >NUL 2>nul
)
It is a very simple batch file for what it does, but falls flat on it's face with titles containing underscores.
A few things:
Searching for _2016 would mean the batch file would need yearly maintenance. Could we either search for system %YEAR% or somehow search for "_####_##_##_" with something like a regular expression to get away from searching for system date or a specific year?
EDIT:
While not ideal as the switches are useful, I found a way in the software to not export the project specific switches at the end of the file name. So now the export would be:
PROJECTTITLE_2016_10_07__09_45_11.iges
PROJECTTITLE_2016_10_07__09_45_11.step
Which I know I can trim from right, what, 21 characters, use that name to make a folder and search the directory for all files containing that trimmed string.
It still would be nice to figure out how to search for the specific string though with the switches intact. I am willing to learn, so throw all explanations of your code you can at me.
Double (Late) EDIT:
First, thank you all for answering this, I deeply appreciate your help.
Double underscores in the the filename are quite rare, but do happen, probably due to typos. It becomes more of an issue with the volume of files I'm planning to move with this. The software runs on maybe 100 user machines with 20 or so being heavy users, each saving up to maybe 1000 files a day. The software will automatically save in increments, as the user runs the simulation. I'm trying to give them a way to collaborate and view each other's simulation results over the network (that we actively encourage them to use) and it figures that the software is hard coded to output to the C drive (for "performance" as the vendor tells me). I'm looking into scheduling the files to move every 15 minutes on every PC in their OU instead of nightly to give a near-real-time view on what they are working on.
Another option I explored was symbolically linking the output folder on each machine to the software's folder network drive, but found that this really doesn't solve the user's "organization" issue, putting like project runs in the same folder. This also has the issue of not allowing them to save a project out of the office without VPN, which some users do do, then move their files over when they get back in the office.
Thank you for your assistance.
Next batch script should do the job even if a file name contains cmd poisonous characters like space or % percent sign etc.
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_fouts=C:\Output" your setting
set "_fouts=D:\test\39924063" my setting
for /F %%G in ('wmic OS get localdatetime ^|find "."') do set "_fyear=%%G"
pushd "%_fouts%"
set "_fyear=%_fyear:~0,4%"
call :doDir
set /A _fyear -= 1
call :doDir
popd
ENDLOCAL
goto :eof
:doDir
rem debugging output echo(%_fyear%
for /f "delims=" %%V in ('
dir /b /a-d "*_%_fyear%_*.iges" "*_%_fyear%_*.step" 2^>NUL') do (
set "_fname=%%~nV" filename without extesion
set "_fexte=%%~xV" extesion only
call :doAll
)
goto :eof
:doAll
call set "_ftail=%%_fname:*_%_fyear%_=%%"
call set "_fproj=%%_fname:_%_fyear%_%_ftail%=%%"
rem debugging output echo("%_fproj%" "%_fname%" "%_fexte%"
ECHO mkdir "I:\ENG\PARTS\%_fproj%" 2>nul
ECHO move "%_fname%%_fexte%" "I:\ENG\PARTS\%_fproj%\"
goto :eof
Output (note that operational mkdir and move commands are merely displayed for debugging purposes using ECHO mkdir and ECHO move, respectively):
==> dir /B /S "D:\test\39924063" /S
D:\test\39924063\#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges
D:\test\39924063\#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step
D:\test\39924063\%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.iges
D:\test\39924063\%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.step
==> D:\bat\SO\39924063.bat
mkdir "I:\ENG\PARTS\#14drop_wire-edm"
move "#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges" "I:\ENG\PARTS\#14drop_wire-edm\"
mkdir "I:\ENG\PARTS\%PROJECT TITLE"
move "%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.iges" "I:\ENG\PARTS\%PROJECT TITLE\"
mkdir "I:\ENG\PARTS\#14drop_wire-edm"
move "#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step" "I:\ENG\PARTS\#14drop_wire-edm\"
mkdir "I:\ENG\PARTS\%PROJECT TITLE"
move "%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.step" "I:\ENG\PARTS\%PROJECT TITLE\"
==>
Resources (required reading, incomplete):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~nV, %~xV etc. special page) Command Line arguments (Parameters)
(set "_fyear=%_fyear:~0,4%" etc.) Extract part of a variable (substring)
(%variable:StrToFind=NewStr% etc.) Variable Edit/Replace
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
REM (
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*__*" '
) DO (
IF /i "%%~xa"==".iges" CALL :process "%%a"
IF /i "%%~xa"==".step" CALL :process "%%a"
)
REM )>"%outfile%"
GOTO :EOF
:: Process filename "%1"
:process
SET "fullname=%~1"
SET "junk=%fullname:*__=%"
CALL SET "project=%%fullname:%junk%=%%"
SET "project=%project:~0,-13%
ECHO(MD "%destdir%\%project%"
ECHO(MOVE "%sourcedir%\%~1" "%destdir%\%project%\"
GOTO :eof
You would need to change the settings of sourcedir and destdir to suit your circumstances.
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
This approach simply performs a directory list without directorynames (/a-d) of each file in the source directory that contains a double-underscore. Each filename matching is assigned to %%a and if the extension part (%%~xa) is one of the targets, then process the filename.
Processing consists of removing all of the characters before the double-underscore and then removing that junk part from the full name, giving project+date. Remove the last 13 characters and you have your project name.
Will have problems with any filename containing certain symbols like % or = but should be fine with underscores.
This version assumes there will not be an instance of _YYYY_ in the PROJECTTITLE.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
(Set OutDir=I:\ENG\PARTS)
(Set SrcDir=C:\Output)
If Not Exist "%SrcDir%\" Exit/B 1
If Not Exist "%OutDir%\" Exit/B 1
For /F "EOL=Y" %%A In ('WMIC Path Win32_LocalTime Get Year') Do (
For /F "Delims=" %%B In ("%%A") Do Set "ThisYr=%%B")
For /F "Delims=" %%A In ('Where "%SrcDir%:*_%ThisYr%_*.iges"') Do (
If Exist "%%~dpnA.step" Call :Sub %%~nA)
Exit/B
:Sub
Set "BigTit=%~1"
For /F "Delims=" %%A In ('CMD /Q /C "Call Echo %%BigTit:_%ThisYr%_=&:%%"') Do (
If Not Exist "%OutDir%\%%A\" MD "%OutDir%\%%A"
Move "%SrcDir%\%~1*.*" "%OutDir%\%%A">Nul)
Edit, there is no need to export without the potentially useful project switches using the above code.
Supposing the PROJECTTITLE part of the file names does not contain two consecutive underscores, you could use the following script, which splits off the first occurrence of __ and everything after (so the time part and the optional switches are removed), using a standard for loop rather than for /F; then it splits off another 11 characters (hence the remaining date part), using sub-string expansion:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=."
set "_TARGET=."
for /F delims^=^ eol^= %%F in ('
pushd "%_SOURCE%" ^&^& ^(
dir /B /A:-D ^
"*_????_??_??__??_??_??*.iges" ^
"*_????_??_??__??_??_??*.step" ^
^& popd^)
') do (
call :PROCESS "%%F"
)
endlocal
exit /B
:PROCESS val_file
setlocal DisableDelayedExpansion
set "FILE=%~1"
setlocal EnableDelayedExpansion
for %%I in ("!FILE:__=";"!") do (
endlocal
set "ITEM=%%~I"
setlocal EnableDelayedExpansion
goto :NEXT
)
:NEXT
if defined ITEM (
set "ITEM=!ITEM:~,-11!"
md "%_TARGET%\!ITEM!" 2> nul
if not exist "%_TARGET%\!ITEM!\!FILE!" (
move /Y "%_SOURCE%\!FILE!" "%_TARGET%\!ITEM!\" > nul
)
)
endlocal
endlocal
exit /B
Finally I come up with a script that is able to handle even files whose PROJECTTITLE part contain __ on their own. It splits off the last occurrence of __ and everything after (so the optional switches are removed, if any, or the time part is removed otherwise), using a standard for loop rather than for /F; then it splits off another 21 characters (hence the remaining date and time parts), or, if no optional switches were present, just another 11 characters (hence the remaining date part), using sub-string expansion:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=."
set "_TARGET=."
for /F delims^=^ eol^= %%F in ('
pushd "%_SOURCE%" ^&^& ^(
dir /B /A:-D ^
"*_????_??_??__??_??_??*.iges" ^
"*_????_??_??__??_??_??*.step" ^
^& popd^)
') do (
call :PROCESS "%%F"
)
endlocal
exit /B
:PROCESS val_file
setlocal DisableDelayedExpansion
set "FILE=%~1"
set "BASE=%~n1"
set "NAME=" & set "ITEM="
setlocal EnableDelayedExpansion
for %%I in ("!BASE:__=";"!") do (
for /F "delims=" %%E in ("!NAME!!ITEM!__") do (
endlocal
set "NAME=%%E"
set "ITEM=%%~I"
setlocal EnableDelayedExpansion
)
)
if defined NAME (
set "NAME=!NAME:~2,-2!"
echo("!ITEM!"| > nul findstr /R "^\"[0-9][0-9]_[0-9][0-9]_[0-9][0-9]\"$" || (
if defined NAME set "NAME=!NAME:~,-10!"
)
if defined NAME set "NAME=!NAME:~,-11!"
if defined NAME (
md "%_TARGET%\!NAME!" 2> nul
if not exist "%_TARGET%\!NAME!\!FILE!" (
move /Y "%_SOURCE%\!FILE!" "%_TARGET%\!NAME!\" > nul
)
)
)
endlocal
endlocal
exit /B

Batch - Find string in text file and delete full line

I use the script from this Thread accepted answer from Mofi. The script copy folders and store them in text file to exclude once copied folders on next run.
Sometimes I have folders called [incomplete]-different.names and I do not want to copy this folders. I want that all folders with the string [incomplete]- and the name behind are skipped or are not even written in the text file %CurrentList% for further processing.
These are my previous attempts but so far I could not get up and running with the script from the top.
Help would be nice, and thanks in advance.
Try 1:
for /f "delims=" [incomplete]-%%D in ("%CurrentList%") do (
set str=%%D
set str=!str: =!
set str=!str: %%D =!
echo !str!
Try 2:
findstr /v /b /c:"[incomplete]-"%%D" "%CurrentList%" del "%%D"
You were really close with your second attempt.
If all you want is to delete lines in %CurrentList% that contain the string [incomplete]-, you can just direct the output of a findstr /v to a temp file and then overwrite CurrentList with that file.
findstr /v /c:"[incomplete]-" "%CurrentList%" >tmpList.txt
move /y tmpList.txt "%CurrentList%" >nul

Batch file search & create with more than one word

I need your help, I am fairly new at this type of scripting, and I need your help to try and get this script to function correct.
I have a script that searches a folder for files and moves them to a folder name after the files first characters. But I have an issue when the files are seperated by more than one '.'.
setlocal EnableDelayedExpansion
set "IncomingFolder=D:\Test"
set "showsFolder=D:\Test\"
for %%F in ("%incomingFolder%\*.S*.*") do ( for /f "delims=.S" %%A in ("%%~nF") do (
if not exist "%showsFolder\%" md "%showsFolder%\%%A"
move "%%F" "%showsFolder%\%%A" ) )
For example:
If the files is Hustle.SXX.XXX Then it makes the correct folder named "Hustle".
But if it is named The.Hustle.SXXX.XXX then it makes a folder called "The" only, I need it to use the whole name until ".S".
Anybody who can help me with this?
#ECHO OFF
SETLOCAL
set "IncomingFolder=c:\sourcedir"
set "showsFolder=D:\Test"
for %%F in ("%incomingFolder%\*.S*.*") do (for /f "delims=." %%A in ("%%~nF") do (
ECHO md "%showsFolder%\%%A"
ECHO move "%%F" "%showsFolder%\%%A\"
)
)
GOTO :EOF
I've changed the directory names to suit my system.
I could not recreate the problem you describe, but delims=.S would make the delimiters . or S, not .S. That may be what you are seeing.
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
Also, the required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
You can't use FOR /F to parse from the front because you don't know how many . may appear in the name. I'm assuming you are expecting names like part1.part2.Spart3.part4, but not like part1.part2.Spart3.part4.part5. In other words - you don't want two dots after the .S. If so, then you can safely remove everything after the second to last dot. That is easily done using the ~n modifier twice.
for %%F in ("%incomingFolder%\*.S*.*") do for %%A in ("%%~nF") do (
if not exist "%showsFolder%\%%~nA" md "%showsFolder%\%%~nA"
move "%%F" "%showsFolder%\%%~nA\"
)
(Tickled by Magoo - % missing on "incoming" and ~n required on move-destination)
This uses a helper batch file called repl.bat - download from: https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
Place repl.bat in the same folder as the batch file or in a folder that is on the path.
Test this to see how it goes:
#echo off
set "IncomingFolder=D:\Test"
set "showsFolder=D:\Test"
for %%F in ("%incomingFolder%\*.S*.*") do (
for /f "delims=" %%A in (' echo "%%~nF"^|repl ".(.*)S\d\d.*" "$1" ') do (
md "%showsFolder%\%%A" 2>nul
move "%%F" "%showsFolder%\%%A"
)
)
setlocal EnableDelayedExpansion
set "IncomingFolder=D:\Test"
set "showsFolder=D:\Test"
for %%F in ("%incomingFolder%\*.S*.*") do (
set "file=%%~nF"
for /F "delims=" %%A in ("!file:*.S=!") do set "folder=!file:.S%%~A=!"
if not exist "%showsFolder%\!folder!" md "%showsFolder%\!folder!"
move "%%F" "%showsFolder%\!folder!"
)
set "file=%%~nF" get the file name, for example: set "file=The.Hustle.SXXX.XXX"
!file:*.S=! is the part after the first ".S", for example XXX.XXX, so
set "folder=!file:.S%%~A=!" is file name without ".SXXX.XXX", for example: "The.Hustle"

Is it possible rename all files in a directory to 0.jpg, 1.jpg, 2.jpg, etc?

I have a bunch of images (100+) in a directory, all with different names. Is there any way to rename them, possibly with a script (I'm running Windows), to 0.jpg, 1.jpg, 2.jpg, etc... without having to rename each one individually? I could launch a Linux virtual machine and copy them over if it isn't possible in Windows.
I've got this so far
#echo off
setlocal enableDelayedExpansion
set MYDIR=F:\Pictures\Wallpapers
set /a count = 0
for /F %%x in ('dir /B/D %MYDIR%') do (
echo %%x
#echo !count!
set /a count+=1
)
Which display the correct file name and the correct counter, but when I try
ren %%x !count!.jpg
Tells me "The system could not find the file specified."
You are not providing the full path for the source file. Don't forget that %%x is just the file name; you need to prepend %MYDIR% to have a complete path:
ren %MYDIR%\%%x !count!.jpg

Resources