Windows CMD for matching files to directories - batch-file

I have a Windows CMD script that has a bug. The script is supposed to match the first 8 digits (the date) of a file with a directory titled with the same first 8 digits (the date). If successful, the file is moved into that directory & placed in a subfolder (called 'portfolio'). However, the error File not Found is returned.
file: 20230202_example.jpg
directory: 20230202_winter-holiday/portfolio
...the CMD file:
#echo off
for /f "delims=" %%a in ('dir /b /a-d') do (
set "filename=%%a"
set "first8=!filename:~0,8!"
for /f "delims=" %%b in ('dir /b /a-d *%first8%*') do (
if /i "!filename!" neq "%%b" (
move "!filename!" "%%b\portfolio\!filename!"
)
)
)
If I interrogate the directory in Command Prompt:
dir /b /a-d
...I get a full list of the files contained. When the script is run from Command Prompt, for each file contained I get:
File Not Found

Based upon your target file and directory names, you could probably do it without defining variables and therefore the need to delay variable expansion.
Example:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Delims=" %%G In ('Dir "????????_*" /A:-D /B 2^>NUL
^| %SystemRoot%\System32\findstr.exe /R /C:"^202[0123]1[012][12][0123456789]_."
/C:"^19[789][0123456789]0[123456789]0[123456789]_."
/C:"^19[789][0123456789]0[123456789][12][0123456789]_."
/C:"^19[789][0123456789]0[123456789]3[01]_." /C:"^202[0123]0[123456789]3[01]_."
/C:"^19[789][0123456789]1[012]0[123456789]_."
/C:"^19[789][0123456789]1[012][12][0123456789]_."
/C:"^19[789][0123456789]1[012]3[01]_." /C:"^20[01][0123456789]1[012]3[01]_."
/C:"^20[01][0123456789]0[123456789]0[123456789]_." /C:"^202[0123]1[012]3[01]_."
/C:"^20[01][0123456789]0[123456789][12][0123456789]_."
/C:"^20[01][0123456789]0[123456789]3[01]_."
/C:"^20[01][0123456789]1[012]0[123456789]_."
/C:"^20[01][0123456789]1[012][12][0123456789]_."
/C:"^202[0123]0[123456789]0[123456789]_." /C:"^202[0123]1[012]0[123456789]_."
/C:"^202[0123]0[123456789][12][0123456789]_."
') Do For /F "Delims=_" %%H In ("%%~nG") Do For /F "Delims=" %%I In ('
Dir "%%H_*" /A:D /B 2^>NUL'
) Do %SystemRoot%\System32\Robocopy.exe . "%%I\portfolio" "%%G" /Mov 1>NUL 2>&1
I decided to use a little more accuracy in the dates, (it's not perfect because it has no knowlege of how many days are in each month of any year, but should cover dates between 19700101 and 20231231). If you don't want that, you could simplify it by just removing lines 4 through 17:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Delims=" %%G In ('Dir "????????_*" /A:-D /B 2^>NUL
') Do For /F "Delims=_" %%H In ("%%~nG") Do For /F "Delims=" %%I In ('
Dir "%%H_*" /A:D /B 2^>NUL'
) Do %SystemRoot%\System32\Robocopy.exe . "%%I\portfolio" "%%G" /Mov 1>NUL 2>&1

Related

How to rename directory in Windows Command Prompt using pattern?

I have some directories with names in format:
companyName_a13d0116cc
(unique name + underscore + random string)
Is it possible to rename all directories using just CMD like this?
companyName_a13d0116cc -> companyName
This is possible with the following way:
#echo off
for /F "delims=" %%A IN ('dir /B /AD "*_*"') do (
for /F "delims=_" %%B IN ("%%A") do ren "%%~fA" "%%B"
)
For cmd one-line use:
for /F "delims=" %A IN ('dir /B /AD "*_*"') do for /F "delims=_" %B IN ("%A") do ren "%~fA" "%B"

How can I create a log file?

How to save a log .txt file of all deleted files with this code?
Also I need to change code to search for all backup folders in root directory subfolders.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BackupFolder=D:\backup"
set "LastDate="
for /F "delims=." %%I in ('dir "%BackupFolder%\????????.*" /AD /B /ON 2^>nul') do (
if not "!LastDate!" == "%%I" (
for /F "skip=2 delims=" %%D in ('dir "%BackupFolder%\%%I.*" /AD /B /O-D-N /TC') do rd /Q /S "%BackupFolder%\%%D"
set "LastDate=%%I"
)
)
endlocal
This code was written by Mofi and posted as answer on How to remove oldest folder(s) of a group of folders in a folder with several folder groups? He posted also an enhanced version logging the files before deletion, but it was not working for me properly.
I tried with the followed command >> but log.txt file has not been generated.
The attempt to use >> was not shown in the question. How about something like:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BackupFolder=D:\backup"
set "LastDate="
SET "LOGFILE=%TEMP%\%~n0.log"
for /F "delims=." %%I in ('dir "%BackupFolder%\????????.*" /AD /B /ON 2^>nul') do (
if not "!LastDate!" == "%%I" (
for /F "skip=2 delims=" %%D in ('dir "%BackupFolder%\%%I.*" /AD /B /O-D-N /TC') do (
DIR /S /B "%BackupFolder%\%%D" >>"%LOGFILE%"
rd /Q /S "%BackupFolder%\%%D"
set "LastDate=%%I"
)
)
)
endlocal

How to add recursive directory to batch file

I have the following batch file:
#echo off
for /f "delims=" %%F in (
'dir /b /a-d [*]*'
) do for /f "tokens=1* delims=]" %%A in (
"%%F"
) do for /f "tokens=*" %%C in ("%%B") do ren "%%F" "%%C"
I want launch it in the root directory and have it go through all directories and subdirectories performing the actions.
I tried adding /D and /r to the 'for' lines, but it doesn't appear to be working.
Do I need add something like...
for /D /r do
under the #echo off ?
Use either dir or for to get all the files, don't mix it up.
When using dir /S for recursive enumeration, regard that full paths are output rather than pure file names only.
This should do it:
#echo off
for /f "delims=" %%F in (
'dir /s /b /a-d [*]*'
) do for /f "tokens=2* delims=]" %%B in (
"%%~nxF"
) do for /f "tokens=*" %%C in ("%%B") do ren "%%~F" "%%C"
So I just changed the following in your original code:
added /s to dir (returns full paths then);
improved second for options (you never used the first token %%A, so why extract it then?);
replaced set %%F of second for by %%~nxF to just parse the file name (type for /? for details concerning substitution modifiers such as ~n, ~x);
replaced source argument "%%F" of ren command by "%%~F" to not fall into double-double-quote problems (the ~ modifier removes potential double-quotes);
You are using "dir" for the enumeration of files, so add "/s" to the DIR command.
I might refactor what you have like this to make it easier to manage.
This also does recursion.
call :TOP .
goto :EOF
:TOP
setlocal
cd "%~f1"
for /f "delims=" %%F in ('dir /b /a-d [*]*') do call :SubRoutine "%%F"
for /D %%x in (*) do call :TOP "%%x" || (echo FAILED2 "%%x" && exit /b 2)
goto :EOF
:SubRoutine
for /f "tokens=1* delims=]" %%A in ("%~1") do call :SubRoutine2 "%~1" "%%A" "%%B"
goto :EOF
:SubRoutine2
for /f "tokens=*" %%C in ("%~3") do ren "%~1" "%%C"
goto :EOF

File Retention Script

I have a directory that has a 10 sub-directories. Each of these holds different .bak files. I'm trying to create a script that will check to see if X number of files are there and if the number of files exceeds X, it deletes the oldest file. In other words, I want 20 iterations of a .bak file. When the 21st one shows up, I want the batch file to delete the oldest one.
Is this possible?
If so, can I create a single script that looks in all the sub-directories?
Thanks in advance.
Two options included. The first one will leave %maxFiles% bak files under each of the folders. The second one (windows Vista or later OS is required as robocopy is used to obtain the sorted list of files) will leave %maxFiles% in total
#echo off
setlocal enableextensions disabledelayedexpansion
set "rootFolder=%cd%"
set "maxFiles=20"
rem Option 1 - Keep %maxFiles% inside each of the subfolders
for /d /r "%rootFolder%" %%z in (*) do for /f "skip=%maxFiles% delims=" %%a in (
'dir /tc /o-d /a-d /b "%%~fz\*.bak" 2^>nul'
) do echo del "%%~fz\%%~nxa"
echo ------------------------------
rem Option 2 - Keep %maxFiles% in total under all the subfolders
for /f "skip=%maxFiles% tokens=2,*" %%a in ('
robocopy "%rootFolder%" "%rootFolder%" *.bak /l /nocopy /is /s /njh /njs /ndl /nc /ns /ts
^| findstr /v /r /e /i /c:"%rootFolder:\=\\%\\[^\\]*"
^| sort /r
') do echo del "%%b"
del commands are only echoed to console. If the output is correct, remove the echo command to remove the files
assumes that you want to check the number of files from the parent directory.Can be done also for each sub-directory.
#echo off
setlocal
set "max_number_files=20"
set "parrent_dir=c:\whatever_you_need"
set "extension=.bak"
pushd "%parrent_dir%"
set "count=0"
setlocal enableDelayedExpansion
for /f "delims=" %%a in ('dir /s /b /a:-d /o:-d /t:c *%extension%') do (
set /a count=count+1
if 1!count! GTR 1!max_number_files! (
rem --- remove the echo to activate deletion
echo del /q /f "%%~a"
)
)
popd
endlocal
endlocal
This will check each folder under d:\base\folder and if there are more than 20 *.bak files it will remove the oldest ones so only 20 *.bak file remain, in each folder.
Test it on some sample folders.
#echo off
for /d /r "d:\base\folder" %%a in (*) do (
pushd "%%a"
for /f "skip=20 delims=" %%b in ('dir /b /a-d /o:-d *.bak ') do del "%%b"
popd
)

Batch Search combo Z: Test List

for /f "tokens=* delims=" %%a in ('dir "recordings.txt" /s /b') do (
echo %%a
)
Is this the correct format to look on the Z: drive for files in the recordings.txt?
Tried powershell don't have permissions on the server
Contents of the file just have the file name / extension
3030009948_3030009912_df1389947f0fb80d62832122.sasf
The Directory structure of Z: is as follows
MM\dd\hh\mm\
recordings.txt is on the Desktop of my userprofile
I also need the paths of the found files
This should read recordings.txt on your desktop and create recordings-results.txt in the same place with the full path to every file inside it.
#echo off
dir /b /s /a-d "z:\" >"%temp%\results.tmp"
del "%userprofile%\desktop\recordings-results.txt" 2>nul
for /f "usebackq delims=" %%a in ("%userprofile%\desktop\recordings.txt") do (
echo finding "%%a"
findstr /i /c:"%%a" "%temp%\results.tmp" >>"%userprofile%\desktop\recordings-results.txt"
)
del "%temp%\results.tmp"
pause
This should be even faster:
#echo off
dir /b /s /a-d "z:\" >"%temp%\results.tmp"
findstr /i /g:"%userprofile%\desktop\recordings.txt" "%temp%\results.tmp" >"%userprofile%\desktop\recordings-results.txt"
del "%temp%\results.tmp"
pause
Dir is to look into a directory if you want to get a value from a file use :
for /f "tokens=*" %%a in ('type "Z:\recordings.txt"') do (
echo %%a
)

Resources