Batch file, loop on folder seems to freeze - batch-file

I need to delete with a batch a list of directories (and subdir) which name starts with a number.
My tree is something like that:
|- root
|--event=aaa
|--photo
|--123
|--44
|--23
|--89
|--otherdir
|--event=bbb
|--photo
|--432
|--67
|--12
|--32
|--otherdir
I found this working example: http://www.dostips.com/forum/viewtopic.php?f=3&t=1496
And this is what I wrote
#ECHO OFF
SET path=\\mypath
SET dir=\parentDir\
:: loop on event=* folders
FOR /D /R %path%%dir% %%K IN ("*event*") DO (
:: if an event contains photos ..
IF EXIST %%K\photo (
ECHO %%K
:: loop on dir inside photo folder with a numeric name
PUSHD %%K\photo ||goto :eof
FOR /f "delims=" %%a IN ('dir /ad /b /s ^|findstr /rc:"\\[0-9]"') DO (
IF EXIST %%~a (
RD /s /q "%%~a"
)
)
POPD
) ELSE (
ECHO.%%K /photo does not exists
)
)
ECHO.completed
PAUSE
the only problem I found is that the execution seems to freeze when the last /event=xxx folder, and takes quite a long time to ECHO the last line ("completed"). I don't understand why .. any ideas?
Many thanks

You can try this. It will delete every folder under the *event* folders that have only numbers in the names.
Currently it will pause on each main folder after merely listing the set of subdirectories that would be deleted, and is not destructive. If the commands look right then remove the echo and the pause to activate the RD command to actually delete the folders.
#echo off
for /f "delims=" %%a in (' dir "*event*" /ad /b ') do (
for /f "delims=" %%b in (' dir "%%a" /ad /b /s ') do (
for /f "delims=0123456789" %%c in ("A%%~nxb") do (
if "%%c"=="A" if exist "%%b\" echo rd /s/q "%%b"
)
)
pause
)

#ECHO OFF
SETLOCAL
SET mypath=.
SET dir=\parentdir\
FOR /f "delims=" %%i IN (
' dir /ad /s /b "%mypath%%dir%" ^|findstr /r "\\.*event.*\\photo\\[0-9].*" ' ) DO (
IF EXIST "%%i" ECHO RD /s /q %%i
)
This should do as you ask - with some cautions.
I've changed the variable names. PATH is not a good name to use because PATH is the sequence of directories which the OS searches for an executable.
I've also changed the value to suit my system.
I've added an ECHO keyword rather than arbitrarily deleting the target directories - just in case of a typo - gives you a chance at verifying first. This ECHO would need to be removed to activate the delete functionality.
The findstr regular expression is \ (which requires an extra \ as an escape) any number of any characters, event, any number of any characters, \photo\, a digit then any number of any characters.
Please also note that the "broken label" form of comment (::) should not be used within a loop. Whereas it (and labels) works within a loop in W7 (and presumably later,) it terminates the loop in some earlier Windows editions, whereas REM works for all editions.

Related

Updating Sub folder and File renaming batch script

Need a bit of help with this script
for /d %%D in ("*") do (
for %%F in ("%%D\*.jpg") do (
ren "%%~dpF(*).txt" "(*) %%~nF.*"
)
)
This is the original script and this is what it does
Before
filename.jpg
(1).txt
Result
filename.jpg
(1) filename.txt
it copies the filename from the jpg and adds it to the filename of the txt file
what I have been trying to do is two things
I want to add a controlled Sub folder reader to it, and I would like to the filename to be copied between certain points of the txt files
Before
filename.jpg
(1)(name).txt
Result
filename.jpg
(1) filename (name).txt
I have tried like 10 different ways to make this work and for some reason I can't
tried this
FOR /f "delims=" %%q IN ('dir /b /s /a-d "Ready\(*)(Name).txt"') DO call :label "%%q"
goto :eof
:Label
set "FILE=%~1"
for /d %%D in ("*") do (
for %%F in ("%%D\*.jpg") do (
ren "%%~dpF(*)(Name).txt" "(*) %%~nF (*).*"
)
)
and I removed this as well for /d %%D in ("*") do (
and tried this
FOR /f "delims=" %%q IN ('dir /b /s /a-d "Ready\(*)(Name).txt"') DO call :label "%%q"
goto :eof
:Label
set "FILE=%~1"
for %%F in ("*.jpg") do (
ren "%%~dpF%~1" "(*) %%~nF (*).*"
)
and tried this
for /d %%D in ('dir /b /s /a-d "*"') do (
for %%F in ("%%D\*.jpg") do (
ren "%%~dpF(*)(Name).txt" "(*) %%~nF (*).*"
)
)
Any help would be great
Thank you
#ECHO OFF
SETLOCAL
rem The following setting for the source directory is a name which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
PUSHD "%sourcedir%"
for /d %%B in ("*") do (
for %%E in ("%%B\*.jpg") do (
FOR /f "tokens=1,2delims=()" %%q IN ('dir /b /a-d "%%~dpnxB\(*)(*).txt" 2^>nul') DO (
rem files matching "(*)(*).txt only
REN "%%~dpnxB\(%%q)(%%r).txt" "(%%q) %%~nE (%%r).txt"
)
FOR /f "tokens=1*delims=()" %%q IN ('dir /b /a-d "%%~dpnxB\(*).txt" 2^>nul') DO IF /i "%%r" equ ".txt" (
rem files matching "(*).txt only
REN "%%~dpnxB\(%%q).txt" "(%%q) %%~nE.txt"
)
)
)
popd
GOTO :EOF
Caution : This batch is armed. It will rename files. Always verify against a test directory before applying to real data.
The outer loop on %%B gets the directory names. No surprise there.
The next loop on %%E gets the .jpg names. No surprise there.
The first loop on %%q looks at the .txt files that fit the pattern (*)(*).txt and re-assembles the parts as required for the rename.
The second loop on %%q looks at the .txt files that fit the pattern (*).txt which may include the just-renamed files matching (*)(*).txt now (*) jpgfilename (*).txt, so this time, %%r must be .txt to exclude these newly-renamed files.
I'll repeat
Caution : This batch is armed. It will rename files. Always verify against a test directory before applying to real data.

Copy everything under a non specific (*) folders

I'm trying to copy some non specific folders with their content, but can't find a way to do it. My problem is every time I try to use any of the copy commands it tells me it's an "Invalid number of parameters", or "0 File(s) copied", or "File not found -", or it copies everything from Folder1, (not just the non specific folders).
What I mean by "non specific" is a folder which has an unknown name, i.e. *.
This is what I have tried:
xcopy /y "C:\Folder1\Something_*" "C:\Folder2"
copy /y "C:\Folder1\Something_*" "C:\Folder2"
robocopy "C:\Folder1\Something_*" "C:\Folder2"
/+ adding " * " in front of "Something_*"
I have also tried a lot more smaller things, that I don't see a need to add.
I'm a little lost on what to do at this point, and feel like I have been looking everywhere for a solution with no luck.
Edit: i found a way to do this and it's so much better, this is how
for /R "%sourcedir%" %%A in (Something_*) do copy /y "C:\Folder1\%%~A" "C:\Folder2"
#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files\t w o"
SET "destdir=u:\your results"
:: Version 1 - all files arrive in the destination directory
FOR /f "delims=" %%b IN ('dir /b /ad "%sourcedir%\Something_*" ') DO (
COPY /b /y "%sourcedir%\%%b\*" "%destdir%\" >NUL 2>nul
FOR /f "delims=" %%c IN ('dir /b /s /ad "%sourcedir%\%%b" ') DO (
COPY /b /y "%%c\*" "%destdir%\" >NUL 2>nul
)
)
cls
dir/s "%destdir%"
PAUSE
:: This is a routine I use for testing. It simply deletes the directory named and restores it, empty
CALL deltreey /r "%destdir%">NUL
:: Version 2 - preserve tree structure
FOR /f "delims=" %%b IN ('dir /b /ad "%sourcedir%\Something_*" ') DO XCOPY /y /s /e "%sourcedir%\%%b" "%destdir%\" >NUL 2>nul
)
cls
dir/s "%destdir%"
PAUSE
:: This is a routine I use for testing. It simply deletes the directory named and restores it, empty
CALL deltreey /r "%destdir%">NUL
GOTO :EOF

Piping string with folders in variable to findstr - copy and rename files

I'm trying to pipe a string that contains folder paths to findstr to search for a particular part in the names of the given folders - or at least, that is what I'm planning to do.
I've got a source folder with files that have to be copied into multiple subfolders and after that, one of the copied files has to be renamed corresponding to the destination folder. If there already are files with the same names, they have to be overwritten. I am trying to achieve this via .bat-file using the following commands in my code:
pushd ..\..\destination_folder\
FOR /F "delims=" %%i in ('dir /AD /S /B^| findstr /I "._Modul_X$"') do copy ..\xxx\yyy\ressources\*.* %%i
& ren %%i\xxxx_Modul_X.BAT_TEMPLATE" "%%i_Modul_X.BAT_TEMPLATE
The copy-part seems to work, the rename-part does not and when it comes to overwriting the one file that has to be renamed after copying it (name conflict!), I'm pretty clueless how to do this (IF EXIST & DEL?).
If I understand the process you're attempting, then the following should do as you require, subject to my assumption that xxxx is a sequence of exactly four, digits (directory names), and characters (file names):
#Echo Off
SetLocal EnableExtensions
PushD "..\..\destination_folder" 2>NUL || GoTo :EOF
If Not Exist "..\xxx\yyy\resources\*.*" GoTo :EOF
For /F "Delims=" %%G In (
'Dir /B /S /A:D "????_Modul_X" 2^>NUL ^|%__AppDir__%findstr.exe^
/I /R "\\[0123456789][0123456789][0123456789][0123456789]_Modul_X"'
) Do (
For /F "Delims=" %%H In (
'%__AppDir__%where.exe /F "%%G":"????_Modul_X.BAT_TEMPLATE" 2^>NUL'
) Do Del /A /F %%H
Copy /Y "..\xxx\yyy\resources\*.*" "%%G" 1>NUL
For /F "Delims=" %%I In (
'%__AppDir__%where.exe /F "%%G":"????_Modul_X.BAT_TEMPLATE" 2^>NUL'
) Do If /I Not "%%~nxI" == "%%~nxG%%~xI" Ren %%I "%%~nxG%%~xI"
)
Please note that you will probably need to modify both instances of xxx\yyy\resources, (lines 5 and 14), as nobody really uses names like that, paying special attention to the spelling, I've used resources above, not ressources.

Finding a latest folder that contains a specific file

I need to search a directory with multiple folders and check for the latest file(.exe) and copy that to another location.
SET "src_root"
SET "tgt_path"
DIR "%src_root%" /B /AD /O-D /TC > "%TEMP%\dirlist.tmp"
< "%TEMP%\dirlist.tmp" SET /P last_dir=
XCOPY "%src_root%\%last_dir%\*.exe" "%tgt_path%"**
This code helps me copy the EXE file in the latest folder, but in case, there is no EXE in the latest folder, I need to copy it from the folder which contains the latest EXE, can anyone help me out?
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
SET "filename="
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\neo.7z" '
) DO SET "filename=%%a"&set "dirname=%%~dpa"&goto found1
ECHO NOT found!
GOTO :eof
:found1
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\neo.7z" '
) DO IF /i "%dirname%" neq "%%~dpa" FOR /f %%s IN ('XCOPY /y /L /D "%filename%" "%%~dpa"') DO IF "%%s"=="0" SET "filename=%%a"&set "dirname=%%~dpa"&goto found1
ECHO latest file is "%filename%"
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used files named neo.7z for my testing - I believe that you should have a fixed filename in the situation you describe - the directories are no doubt not crammed with *.exe files.
It's very pedestrian, but will do the job.
Essentially, find any file with the required name in the required directory-tree and record the name in filename, directory in dirname.
Using that filename as a base, try xcopying it over every other matching filename. Use the /L flag to list-only, and the /y flag to remove user-intervention. If the return is 1 file(s) copied ,f which only the first token is selected into %%s, then the chosen file is later. 0 file(s) copied sets %%s to 0 and means that the chosen file is earlier, so select the newer file and directorynames and restart.
I'll leave it a a user-exercise to speed it up. (suggestions if interested : delayedexpansion, subroutine and retain-new-startpoint)
Revision [about 5 times faster]
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
SET "filename="
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\neo.7z" '
) DO SET "candidate=%%a"&CALL :latest
ECHO latest file is "%filename%"
GOTO :eof
:latest
IF NOT DEFINED filename GOTO selectnew
FOR /f %%s IN ('XCOPY /y /L /D "%filename%" "%candidate%"') DO IF "%%s"=="1" goto :eof
:selectnew
SET "filename=%candidate%"
GOTO :EOF
This revision avoids the repetitive directory-scan. For each matching filename, compare the newly-found file against the previously-found file using the xcopy /L method, and select the new candidate if the new one is later. continue untill all matching names have been tested.

Batch File Process all files in a directory except files of type

I have a section of script that currently runs through a directory of files 'processing' all files specified before deleting them:
for %%x in (*.J_E, *.J_T, *.J_I, *.bcc) do (
"%%x"=="*.exe" (
set /a count=count+1
set choice[!count!]=%%x
)
echo.
::convert files
md %FreshDate%\%FreshTime%
for /l %%x in (1,1,!count!) do (
echo %%x. !choice[%%x]!
tlv2txt !choice[%%x]! > %FreshDate%\%FreshTime%\!choice[%%x]!.txt
del !choice[%%x]!
)
The list of files that need this processing is growing almost weekly and I think it will probably just be easier to process all files except a small number (.dll, *.exe and *.bat)
I have tried substituting this line at the start of the example above:
for %%x in (*.J_E, *.J_T, *.J_I, *.bcc) do (
with this:
for %%x in (*) do if not "%%x=="*.dll" if not "%%x"=="*.bat" if not "%%x"=="*.exe" (
but all I can manage to do with this is delete everything in the directory - including the batch file running the script!
Can anyone help?
Many Thanks
your if construct won't work. Batch's if is very basic.
Use another method: echo the extension of your file and use findstr to check if the string is not (/v) one of the given ones.
for %%A in (*) do (
echo %%~xA|findstr /v /x ".dll .bat .exe" && (
tlv2txt %%A > %FreshDate%\%FreshTime%\%%~nA.txt
)
)
#echo off
setlocal EnableDelayedExpansion
set "exclude=.dll.exe.bat."
for %%x in (*) do if "!exclude:%%~Xx.=!" equ "%exclude%" (
echo %%x
tlv2txt %%x > %FreshDate%\%FreshTime%\%%~Nx.txt
del %%x
)
In this method the extension of the files is compared vs. a list of excluded extensions in a very simple way: the extension is removed from the list, so if the result is the same, such extension is not in the list. This method don't use any external command, like find or findstr, so it run faster.
Wether inclusion nor exclusion need to be that complicated:
:: Inclusion
For /f "Delims=" %%A in (
'Dir /B *.J_E *.J_T *.J_I *.bcc'
) Do tlv2txt "%%A" > "%FreshDate%\%FreshTime%\%%~nA.txt"
:: Exclusion
For /f "Delims=" %%A in (
'Dir /B ^| findstr /i /V ".bat$ .cmd$ .exe$ .dll$" '
) Do tlv2txt "%%A" > "%FreshDate%\%FreshTime%\%%~nA.txt"
I would also remove the unnecessary for loop and just have one:
If Not Exist "%FreshDate%%FreshTime%\" MD "%FreshDate%%FreshTime%"
For /F "Delims=" %%A In ('Dir/B/A-D^|FindStr/VIE "\.dll \.exe \.bat') Do (
tlv2txt "%%A">"%FreshDate%%FreshTime%\%%~nA.txt" 2>Nul
If Not ErrorLevel 1 Del "%%A"))
Please not that I was unable to determine the format of your %FreshTime% variable as it was excluded from your code snippet. Please make sure that it doesn't contain a trailing backspace.

Resources