Batch script to automatically delete empty folders - need help adding exceptions - windows

My batch experience is rather limited but I did manage to write the following script to delete all empty subfolders of my target folder.
set "Target=C:\Target"
for /f "delims=" %%i in ('dir "%Target%" /A:D /B /S ^| sort /r') do rd "%%i" 2>NUL >NUL
My problems are:
1. I would like to be able to keep the first layer of subfolders intact and only delete empty folders in the following layers.
2. If it is possible I would also like to skip certain folders completely based on their name.
Is it possible to do that or would i need to write the script for all of the subfolders i want to clean up?

The code below was tested on following folder structure in folder C:\Target
Folder1
Folder To Delete
Folder To Keep A
FolderToKeepB
Folder 2
Folder To Keep A
Not Empty Folder
File in Folder.txt
The resulting folder structure after running the batch file below was
Folder1
Folder To Keep A
FolderToKeepB
Folder 2
Folder To Keep A
Not Empty Folder
File in Folder.txt
Just the single folder Folder To Delete was deleted as this one should not be always kept and it was indeed empty.
#echo off
rem For each subfolder in C:\Target do ...
for /D %%D in ("C:\Target\*") do (
rem For each subfolder in found subfolder of C:\Target do ...
for /D %%S in ("%%~D\*") do call :DeleteFolder "%%~S"
)
rem This goto :EOF results in exiting the batch file.
goto :EOF
rem Subroutine for easier comparing the name of the current
rem subfolder with the name of the subfolders to always keep.
rem The goto :EOF commands below just exit the subroutine.
:DeleteFolder
if "%~nx1"=="Folder To Keep A" goto :EOF
if "%~nx1"=="FolderToKeepB" goto :EOF
rem Delete this subfolder which fails if it is not empty.
rem The error message is suppressed by redirecting output stream
rem stderr (standard error) with handle 2 to the NUL device.
rd "%~1" 2>nul
goto :EOF
For more details on the used commands read help output printed into a console window on running
For command call: call /? or help call
For command for: for /? or help for
For command goto: goto /? or help goto
For command rmdir (rd): rd /? or help rd or rmdir /? or help rmdir
Using command redirection operators

Related

We need to hardcode arguments so all the user need to do is just needs to run the bat file to upgrade the license

We have an updated license stored in the file 'style.mfx'. We want to send to user and have it silently replace the old file by that name. The File will always be in c:.
I've tried this demo with no luck. I want to hard code targetName and replacementFile in the batch file.
#echo off
set targetName=%~NX1
set replacementFile=%~F2
call :processFolder
goto :EOF
:processFolder
rem For each folder in this level
for /D %%a in (*) do (
rem Enter into it, process it and go back to original
cd %%a
if exist "%targetName%" (
copy "%replacementFile%" "%targetName%" /Y
)
call :processFolder
cd ..
)
exit /B
cmd line isn't even working! but I want the arguments in the batch file...
app teststyle.mfx c:\teststyle.mfx
c:\Users\Joseph\Desktop>replace.bat teststyle.mfx c:\teststyle.mfx
c:\Users\Joseph\Desktop>
Any help would be appreciated.
:processFolder
rem For each folder in this level
for /D %%a in (*) do (
rem Enter into it, process it and go back to original
pushd "%%a"
if exist "%targetName%" (
copy "%replacementFile%" "%targetName%" /Y
popd
)
goto :eof
pushd/popd can be used to save-and-return.
reaching end-of-file will return from a called routine.

Deleting Contents of Multiple Directories, Only if They Exist (Batch File)

I'm trying to write a simple batch file that will clean up disk space. I have to delete the entire contents (folders and files) of 4 different directories, but only if they exist. I've been testing trying to delete one, but I know nothing about writing batch files. After all the research I've done, I came up with a couple lines of code that doesn't work.
#echo off
IF EXIST "C:\Windows\TestFolder\TestSubFolder\*.*"
DEL /s /q "C:\Windows\TestFolder\TestSubFolder\*.*"
for /d %%p in ("C:\Windows\TestFolder\TestSubFolder\*.*") do rmdir "%%p" /s /q
exit
In this scenario, I need to be able to delete the contents of TestSubFolder, if TestSubFolder exists. Whether it exists or not, after that action is complete, I need the code to do the same thing to a TestSubFolder2.
Thanks
The main problem in your code is the improper usage of the if command. If there is only one command to execute if the condition is true, it can be written in the same line, but to write the command in the next line you need to use parenthesis. It should be something like
IF EXIST "C:\Windows\TestFolder\TestSubFolder\*.*" (
DEL /s /q "C:\Windows\TestFolder\TestSubFolder\*.*"
for /d %%p in ("C:\Windows\TestFolder\TestSubFolder\*.*") do rmdir "%%p" /s /q
)
But this can be simplified as
2>nul pushd "C:\Windows\TestFolder\TestSubFolder" && (
rmdir . /s /q
popd
)
That is, we try to change to the indicated folder (pushd) and if there was not any problem (conditional execution operator && means execute next command if the previous one did not fail) them remove all the contents of the folder (rmdir) and return to the previous active directory (popd). The 2>nul is just hidding any error message (ex. the folder does not exist, locked files that can not be removed, ...)
Now, if the process has to be repeated for more than one folder, we can use the for command to iterate over the list of the folders
for %%a in ( "folder1" "folder2" ) do ....
Placing the previous code into this for loop we have
#echo off
setlocal enableextensions disabledelayedexpansion
2>nul (
for %%a in (
"C:\Windows\TestFolder\TestSubFolder"
"C:\Windows\TestFolder\TestSubFolder2"
) do pushd "%%~fa" && (
rmdir . /s /q
popd
)
)
The error hidding has been moved to cover all the for execution, and now, for each of the folders (referenced by the for replaceable parameter %%a), we try to change to the folder using the full path (%%~fa) and if we can change to it, then remove all the folder contents before returning to the original active directory.
CD "C:\Windows\TestFolder\TestSubFolder"
RD /s /q "C:\Windows\TestFolder\TestSubFolder"
Works for me.
or from anywhere
RD /s /q "C:\Windows\TestFolder\TestSubFolder"
MD "C:\Windows\TestFolder\TestSubFolder"

Moving files from Subfolders into root directory, but not copying them to the next directory when ran again

I have a folder that contains subfolders with MP4 files. I'm trying to write a script that will move the MP4 files out of the subfolders into the root folder when ran. The batch file I wrote is working, but when the batch script runs again for new subfolders, the MP4 files that were already copied to the root folder, get moved up another level in the file structure. For example:
C:\MainRoot\Root\Subfolder\media.mp4
When script is ran, 'media.mp4' gets moved up to C:\Root\media.mp4 as desired.
But since I need the script to run on a scheduled task. The next time the script runs I get the following:
C:\MainRoot\media.mp4
Instead of just the MP4 file staying in C:\MainRoot\Root.
Here's my batch file so far to copy the mp4 files:
set root_folder=C:\MainRoot\Root
for /f "tokens=1* delims=" %%G in ('dir %root_folder% /b /o:-n /s ^| findstr /i ".mp4" ') do (
move /y "%%G" "%%~dpG..\%%~nxG"
)
What do I need to modify so that once moved, the MP4 files will stay in place?
Any help would be greatly appreciated!
Since all your source files seem to be at a certain directory level, a for /D loop could be wrapped around your for /F loop, which parses the output of a non-recursive dir command line (no /S):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=C:\MainRoot\Root"
set "_PATTERN=*.mp4"
rem // Loop through sub-directories:
for /D %%D in ("%_ROOT%\*") do (
rem // Loop through matching files:
for /F "eol=| delims=" %%F in ('dir /B "%%~fD\%_PATTERN%"') do (
rem // Avoid overwriting destination file:
if not exist "%_ROOT%\%%~nxF" (
rem // Move matching file one level up:
move /Y "%%~fD\%%~nxF" "%_ROOT%\%%~nxF"
)
)
)
endlocal
exit /B
If you are happy to overwrite as in your provided example then something as simple as this may suit your purpose:
#Echo Off
Set root_folder=C:\MainRoot\Root
If /I NOT "%CD%"=="%root_folder%" PushD "%root_folder%" 2>Nul||Exit/B
For /R %%G In (*.mp4) Do If /I NOT "%~dpG"=="%root_folder%\" Move "%%G">Nul 2>&1
If the files are only one folder deep you may prefer this:
#Echo Off
Set root_folder=C:\MainRoot\Root
If /I NOT "%CD%"=="%root_folder%" PushD "%root_folder%" 2>Nul||Exit/B
For /D %%G In (*) Do Move "%%G\*.mp4">Nul 2>&1

Searching for string in multiple zip archives

Here's what I have;
On a windows-based web server there are roughly 1,000 zip files, each with dozens of log files inside. I already have a script that goes through each archive and deletes all but one specific file type (in an attempt to save diskspace and delete things I don't need). Then, the script unzips each archive to their own folder. And I know how to code the reverse of that to zip them back when I'm done.
Here's what I need to figure out;
Once I run the previously mentioned script (we call it garbageman because it cleans out the garbage in the zip files) I need to go through the remaining 5 or 6 files in each of the newly created unzipped folders, and look for a specific string in each file. If I find the string, I delete everything that is not that string, and save it to a file called "export.txt" in that folder. Then, I move to the next unzipped file, and so on. Once completed, I need re-zip everything back together into their own archives
Here's what I have for code so far. Any help is extremely appreciated.
cd "C:\Program Files\7-Zip"
FOR %%c in (C:\Users\xxxxxx\Desktop\LogQueue\*.*) DO 7z d %%c "-x!xstore*" -r
FOR /R "C:\Users\xxxxxx\Desktop\LogQueue" %%I in ("*.zip") do (
"%ProgramFiles%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
)
cd "C:\Users\xxxxxxx\Desktop\LogQueue"
FOR /R "C:\Users\xxxxxx\Desktop\LogQueue" %%I in ("*.*") do (
findstr "xxxxxxxx_eReceipt" %%~fI > %%~dpnI\export.txt
pause
)
for /d %%X in (*) do "c:\Program Files\7-Zip\7z.exe" a "%%X.zip" "%%X\"
This is an edit:
This script should do what you want.
Only Change sourcedir and mystring variables.
export.txt will be inside a file called Storage in the root directory of the batch.
:ScriptA
#ECHO ON
MKDIR "%CD%\Storage"
MKDIR "%USERPROFILE%\Desktop\Outx"
GOTO :ScriptB
:ScriptB
::REM ONLY CHANGE
SET "sourcedir=%USERPROFILE%\Desktop\Test"
FOR /R "%sourcedir%\" %%a in (*.txt) do copy "%%a" "%CD%\Storage"
:ScriptC
:ScriptC
#ECHO OFF
SETLOCAL
SET "VARA=%CD%\Storage"
SET "VARB=%USERPROFILE%\Desktop\Out"
::REM ONLY CHANGE
SET "mystring=PUT_STRING_HERE"
FOR %%a IN ("%VARA%\*.txt") DO FINDSTR "%mystring%" "%%a">nul&IF NOT ERRORLEVEL 1 FINDSTR "%mystring%" "%%a">"%VARB%\%%~nxa"
DEL /F "%CD%\Storage\*.txt"
GOTO :ScriptD
:ScriptD
#ECHO ON
COPY /B "%USERPROFILE%\Desktop\Outx\*.txt" "%CD%\Storage\export.txt"
RD /S /Q "%USERPROFILE%\Desktop\Outx"
goto :eof

Find all files and copy to another destination keeping the folder structure

I have a folder structure with a bunch of *.jpg files scattered across the folders.
Now I want to find some files listed in a CSV file (one column only) or a text file line by line like
one.jpg
ten.jpg
five.jpg
and copy all those *.jpg files to another folder keeping the folder structure like:
outputfolder\somefolder\somefolder\one.jpg
outputfolder\somefolder\ten.jpg
outputfolder\somefolder\somefolder\somefolder\five.jpg
How can I achieve this?
Here is what I've tried
#echo off
CLS
REM CHECK FOR ADMIN RIGHTS
COPY /b/y NUL %WINDIR%\06CF2EB6-94E6-4a60-91D8-AB945AE8CF38 >NUL 2>&1
IF ERRORLEVEL 1 GOTO:NONADMIN
DEL %WINDIR%\06CF2EB6-94E6-4a60-91D8-AB945AE8CF38 >NUL 2>&1
:ADMIN
REM GOT ADMIN RIGHTS
COLOR
1F ECHO Please wait...
FOR /R "%~dp0" %%I IN (.) DO
for /f "usebackq delims=" %%a in ("%~dp0list.txt") do
echo d |xcopy "%%I\%%a" "C:\B2B_output_files" /e /i
COLOR 2F
PAUSE
GOTO:EOF
:NONADMIN
REM NO ADMIN RIGHTS
COLOR 4F
pause
GOTO:EOF
Stack Overflow is not a free code writing service, see help topic What topics can I ask about here?
However, I have nevertheless written the entire batch code for this task. Learn from this commented code and next time try to write the batch code by yourself and ask only if you stick on a problem you can't solve by yourself after several trials and not finding a solution on Stack Overflow or any other website.
The paths of source and target base folder must be defined at top of the batch script below.
The text file containing the name of the files to copy line by line must be named FileNames.txt and must be stored in source base folder with using batch code below.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Define source and target base folders.
rem Note:
rem The paths should not contain an equal sign as then the
rem string substitutions below would not work as coded. The
rem target base folder can be even a subfolder of the source
rem base folder.
set "SourceBaseFolder=C:\Temp"
set "TargetBaseFolder=C:\Temp\OutputFolder"
rem Set source base folder as current directory. The previous
rem current directory is restored by command endlocal at end.
if not exist "%SourceBaseFolder%\*" (
echo %~nx0: There is no folder %SourceBaseFolder%
set "ErrorCount=1"
goto HaltOnError
)
cd /D "%SourceBaseFolder%"
if not exist "FileNames.txt" (
echo %~nx0: There is no file %SourceBaseFolder%\FileNames.txt
set "ErrorCount=1"
goto HaltOnError
)
rem For each file name in text file FileNames.txt in
rem source base folder the loops below do following:
rem 1. Search recursively for a file with current file name
rem in entire directory tree of source base folder.
rem 2. If a file could be found, check its path. Skip the
rem file if the path of found file contains the target
rem folder path to avoid copying files to itself. This
rem IF condition makes it possible that target base
rem folder is a subfolder of source base folder.
rem 3. Create the folders of found file relative to source
rem base path in target base folder. Then check if this
rem was successful by verifying if the target folder
rem really exists and copy the file on existing folder or
rem output an error message on failure creating the folder.
set "ErrorCount=0"
for /F "usebackq delims=" %%N in ("FileNames.txt") do (
for /R %%J in ("%%N*") do (
set "FilePath=%%~dpJ"
if "!FilePath:%TargetBaseFolder%=!" == "!FilePath!" (
set "TargetPath=%TargetBaseFolder%\!FilePath:%SourceBaseFolder%\=!"
md "!TargetPath!" 2>nul
if exist "!TargetPath!\*" (
echo Copying file %%~fJ
copy /Y "%%~fJ" "!TargetPath!" >nul
) else (
set /A ErrorCount+=1
echo Failed to create directory !TargetPath!
)
)
)
)
:HaltOnError
if %ErrorCount% NEQ 0 (
echo.
pause
)
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... for an explanation of %~nx0
copy /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
pause /?
rem /?
set /?
setlocal /?
And read also the Microsoft article about Using command redirection operators to understand 2>nul for suppressing error messages written to STDERR.
The following code should do what you asked for:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LISTFILE=copylist.txt"
set "SOURCE=.\source"
set "DESTIN=.\destin"
for /F "usebackq eol=| delims=" %%L in ("%LISTFILE%") do (
for /F "eol=| delims=" %%F in ('
cd /D "%SOURCE%" ^
^& xcopy /L /S /I /Y ".\%%~L*" "%TEMP%" ^
^| findstr /I /R "^\..*\\%%~L$"
') do (
2> nul md "%DESTIN%\%%F\.."
copy /B /-Y "%SOURCE%\%%F" "%DESTIN%\%%F"
)
)
endlocal
exit /B
It relies on the fact that xcopy outputs relative paths to the console if a relative source path is given, and that it features a switch /L that tells it not to copy anything but list what would be copied without the switch. There is also the switch /S which defines to search for the source item recursively also within subdirectories.
There is a small problem though which requires to be worked around: xcopy /S only walks through subdirectories if source contains a wildcard * or ?, but not if a dedicated file name is given. That is why * is appended to the file name. Since this could also match some unintended items of course, findstr is used to filter them out.
So basically there is a for /F loop that iterates through the items listed in the text file copylist.txt. Within this loop another for /F is nested that enumerates the output of the aforementioned findstr-filtered xcopy /L /S output, which receives the items of the outer loop one after another. The embedded cd command ensures to be in the source directory. The destination of xcopy is just an existing directory to avoid error messages (remember nothing is actually copied due to /L).
The inner loop bopy contains an md command that creates the destination directory (tree), if not existing (2> nul avoids error messages if has already been created earlier), and a copy command which actually performs the copying activity; the switch /-Y defines to prompt the user in case an item already exists at the destination location, you can change it to /Y to overwrite without asking.

Resources