Recursively search for FOLDERS from list and move - batch-file

Need help with searching all sub folders. The current script works fine but only in the top directory. Any help?
md "C:\users\%username%\desktop\People"
SET LOGFILE=C:\users\%username%\desktop\movelog.txt
for /f "delims=" %%i in (people.txt) do (
move "%%i" C:\users\%username%\desktop\People >nul 2>&1
if errorlevel 1 (
echo %%i : Move failed >> %LOGFILE%%
) else (
echo %%i : Move successful >> %LOGFILE%
)
)

Assuming that im reading your question correctly, you want to be able to use the script from any location to find a folder thats specified within your text file to be moved to the new location correct? On linux machines a simple find * "foldername"|grep "foldername" would present usable code to find the files your looking for. Windows does have something similar but not nearly as easy as the linux version.
You can use the following code dir \ /A:D /B /S /O:G|find "%%i" to search for the folder recursively. However the code will output ALL instances of the particular string thats passed to it, which includes the file path for EVERYTHING thats in the particular folders contents. What you would be asking is to move all folders under that name to the new location.
Because of this, there needs to be some sort of identifier in each users folder as so to let the sorting program know that this is what im looking for and nothing else. If i had a blank text file labeled marker.txt in all the particular folders, i can run the code as dir \ /B /S|find "%%i\marker.txt" and this provides a unique marker for the searching program to identify with. This can be stored and sorted later into a variable so for example i had a marker.txt I can then run a simple set path=dir \ /B /S|find "%%i\marker", and make the new movement variable as move %path%\... So unless you have a file that is commonly shared by all of these, you may find it difficult to sort them.

Related

Open multiple directories without knowing the names of said directories and delete folders within them using a Windows batch file

Okay, I do not really know how to describe fully what I want and I feel bad for asking something so advanced. I do not know how to do anything other than move folders and delete files and folders using batch.
I am trying to make a batch file to delete certain Steam files and folders which are used to cache data. I could easily make this for myself and call it a day however I would like to share it and have it work for other people also. The problem is one of the cache folders is named with a unique Steam identifier. I will put what I have made so far below.
REM Makes a temporary folder.
mkdir %LocalAppData%\Temp\steam_cache
REM Deleted all none essential files in Steam's configuration folder.
move "%ProgramFiles(x86)%\Steam\config\config.vdf" %LocalAppData%\Temp\steam_cache
move "%ProgramFiles(x86)%\Steam\config\loginusers.vdf" %LocalAppData%\Temp\steam_cache
rmdir "%ProgramFiles(x86)%\Steam\config" /s /q
mkdir "%ProgramFiles(x86)%\Steam\config"
move %LocalAppData%\Temp\steam_cache\config.vdf "%ProgramFiles(x86)%\Steam\config"
move %LocalAppData%\Temp\steam_cache\loginusers.vdf "%ProgramFiles(x86)%\Steam\config"
REM Delete all none essential files in Steam's userdata folder.
I will put what the file structure goes like below.
%ProgramFiles(x86)%\Steam\userdata\256283931
As you can see the number at the end is completely random and I do not know how to open that directory without knowing the number first. There are sometimes multiple of these folders with random names if you login with multiple account and I would like the batch file to go into them one by one and delete certain folder inside of them.
I will put below the folders that I would like to delete that are inside of the random numbered folder below.
%ProgramFiles(x86)%\Steam\userdata\256283931\ugcmsgcache
Sorry if what I am asking it too much if so just ignore this post, thanks.
What you are looking for is the for /D loop, which enumerates directories:
rem // Enumerate all directories under `userdata`:
for /D %%I in ("%ProgramFiles(x86)%\Steam\userdata\*") do (
rem // Check if there is really a sub-directory called `ugcmsgcache`:
if exist "%%~I\ugcmsgcache\" (
rem // Do something with the full path, like echoing, for instance:
echo "%%~I\ugcmsgcache"
)
)
If you want to ensure that the name of the enumerated directory/-ies name consist(s) of decimal figures only, you could use dir and findstr, together with a for /F loop:
rem // Change into parent directory, because `dir /B` returns plain directory names:
cd /D "%ProgramFiles(x86)%\Steam\userdata"
rem // Enumerate all directories under `userdata`, whose names are pure numbers:
for /F "delims=" %%I in ('
dir /B /A:D "*" ^| findstr /I /X "[0123456789]*"
') do (
rem // Do something with the full path, like echoing, for instance:
echo "%%~fI\ugcmsgcache"
)
The cd command could also be replaced by pushd and popd.
The ~f modifier ensures that the full path is derived, related to the current working directory.
Note that the pipe (|) needs to be escaped here, because it is in the set of the for /F loop.

Use multiple wildcards in a path in batch file

First of all, there are similar questions on Stack OverFlow like:
Windows - Batch file ignoring multiple wildcards
How to specify multiple wildcards in a folder directory in CMD
However, my use-case is a bit specific (or let's say: I couldn't manage to solve my problem using the lessons learned from the previous forum entries - mind that I am a pure beginner with Batch files).
What I want to do is to grab a file from a certain path, which includes a few subfolders (which change their names) - and copy it to another path which has similar folder structure.
I am currently stuck at the point, that I don't know how to set multiple wildcards in the source path, as it consists of a few things changing. Example:
File in Source:
C:\20170621_Update2017SR1\Polarion_update\_backup-20170627-1602.05\polarion\plugins\com.polarion.alm.tracker_3.17.0\configuration\MyPolarion\page.xml
Target Directory:
C:\Polarion\polarion\plugins\com.polarion.alm.tracker_3.18.2\configuration\My Polarion
Basically only the parts with numbers can change, so I was trying the following:
for /D %%a in ("C:\Polarion\polarion\plugins\com.polarion.alm.tracker*") do set "com.polarion.alm.tracker=%%a"
for /D %%b in ("C:\*_Update*\Polarion_update\_backup-*\polarion\plugins\com.polarion.alm.tracker*") do set "folder=%%b"
echo %com.polarion.alm.tracker%
echo %folder%
set source="%folder%\configuration\MyPolarion\page.xml"
set destination="%com.polarion.alm.tracker%\configuration\My Polarion"
xcopy /s /Y %source% %destination%
I am pretty sure line 2 of my Code contains mistakes - because I don't know if I can set multiple wildcards like this.
The console gives me for line 2:
Echo is on
I don't understand what it means and what should I do.
As I already mentioned in a comment, wildcards can only be used in the very last element of a path (independent on whether this is a file or directory). That is why your command line containing C:\*_Update*\Polarion_update\... fails. However, you can resolve every directory level with wildcards individually, like this:
set "folder="
for /D %%b in ("C:\*_Update*") do (
for /D %%c in ("%%~b\Polarion_update\_backup-*") do (
for /D %%d in ("%%~c\polarion\plugins\com.polarion.alm.tracker*") do (
set "folder=%%~d"
)
)
)
echo "%folder%"
If there are more than one matching directories on any levels, replace set "folder=%%~d" by echo "%%~d" to view them all.

Newbie: Need to find a file, read it, and cd to its directory

EDIT: To clarify what I'm looking to do is move a few files into a data folder of an application. The application is installed into Program Files but it keeps data inside app data. The folder name looks something like this
76053ADAJSQDUC4975
Problem is that it's unique to every instance of the application installed and for every computer that will be using this batch. So I'm in the directory and it has
1AKDHCI4985HF55GHJKB G5586HJFRUK56885KOQQ
The only way to identify the folders is by a .txt file inside each one called
origin.txt
that shows the file path to the applications installation directory (C:/Program Files(x86)/********) on one line.
I figured I can use a for to loop through, find the the file, and read it. What I don't know how to do, is find the right file, and cd to its directory. The second problem is since this batch file will be used by multiple users, not all of their installation paths are the same. So inside .txt it could be C:/, D:/, Program Files or Program Files(x86) so the only thing useful to me is the last several words. How would I go about being selective like that.
I'm currently traveling so can't answer right away but would appreciate if you guys help me out or point me in the right directions. Thanks
First, if the application is installed with an installer which adds something to Windows registry for knowing itself on next run (update/upgrade/uninstall) which version of the application is already installed and into which directory if installed at all, it is better to evaluate this information in registry instead of searching around in file system. See my answer on Locate if the program exists and set a custom variable in batch windows.
Second, with assuming text file origin.txt can be found anywhere within application data directory of current user containing only once (or last) the string :\ as part of the directory with the program files of the application, the following batch code could be used to get the directory path and make it the current directory.
#echo off
set "ApplicationDirectory="
for /F "delims=" %%I in ('dir /A-D /B /S "%APPDATA%\origin.txt" 2^>nul') do (
for /F "delims=" %%D in ('%SystemRoot%\System32\findstr.exe /C:":\\" "%%~I" 2^>nul' ) do (
if exist "%%~D" (
set "ApplicationDirectory=%%~D"
goto ChangeDirectory
)
)
)
echo Could not determine directory of application.
goto :EOF
:ChangeDirectory
cd /D "%ApplicationDirectory%"
echo Directory is: %ApplicationDirectory%
set "ApplicationDirectory="
The first FOR loop uses command DIR to search in all subdirectories of user related application data directory for the file origin.txt. The inner FOR loop is processed if there is at least one such file found.
The inner FOR loop calls FINDSTR to search in found origin.txt for all lines containing the literal string :\ and processes all found lines.
For each line returned by FINDSTR the inner FOR loop checks if there is a directory (or file) using the entire string of the line containing :\.
Both loops are exited immediately on a positive check on existence of directory (or file) with a jump to label ChangeDirectory with the commands to switch the current directory independent on current drive and echoing the found application directory.
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.
cd /?
dir /?
findstr /?
for /?
goto /?
if /?
set /?
Note: I strongly recommend to run FINDSTR with a better search string or perhaps even a regular expression than just :\ if file origin.txt could contain multiple paths.
I ended up using
set "ApplicationDirectory="
for /r "%appdata%" %%a in (origin.txt*) do find "thewordsiwaslookingfor" <"%%a" >nul && set "ApplicationDirectory=%%~dpa"
Then I used ApplicationDirectory to be able to move some files into that directory.
Which worked perfectly, for what I was trying to do.

batch Moving all files in 100s of folders up one folder

I have a small issue. I'm not super fluent in batch scripting but i'm trying to get better.
I'm trying to get a script working at my current job that we can use to move all files in the last sub-directory of a parent up one directory.
The need is for moving image sequences delivered with a superfluous sub-directory up one sub-directory for effects workflow
essentially i'm being delivered 100s of image sequences as:
Episode/Footage/shot/resolution/shot.0000001.dpx
I would love a batch script i could move into the "Footage" folder that would parse the shot directories below them and move the image sequences out of the resolution folder and place them directly into the shot folder so the structure would look more like this:
Episode/Footage/shot/shot.0000001.dpx
This batch would need to be reused over many instances and just be robust enough to be reusable regardless of what the extensions on the image sequences are or the naming structure of the subfolders are.
for /f "delims==" %%i in ('dir /a:d /b') do for /f "delims==" %%f in ('dir "%%i" /a:d /b') do (move "%%i\%%f\*" "%%i"&&rd "%%i\%%f" /s /q)
The * can be replaced with * . * (no spaces) to only grab files.
Use % instead of %% for use on the command line.
This will grab from any dir under Footage. Delete the first for loop and replace all occuences of %%i with shot to only grab from there.
#!/bin/bash
mv Episode/Footage/Shot/*/* Episode/Footage/Shot
Or for more Fanciness:
#!/bin/bash
echo "Write the file path:"
read file_path
mv $file_path/*/* $file_path/
This will ask you what the path is (This is Episodes/Footage/shot in your example) then find all the files in that path and all the files inside them and put them all in the path.
You could also modify this if instead of putting the files in the path you want them in a different place you could add:
echo "Write the destination file path:"
read file_path2
in between: read file_path and mv ...
and change:
mv $file_path/*/* $file_path
to:
mv $file_path/*/* $file_path2
There is really no need to go through so much trouble.
With the exceptions of the PUSHD and POPD commands, the whole thing can be placed on one line like nephi12 did.
I'm puting everything on separate lines for clairity's sake, but will give two examples of it on one line later.
REM Set working directory
PUSHD C:\Episode\Footage\
REM Find all the sub directories of the working
REM directory, and if any exist execute the loop below:
For /d %%d in ( *.* ) do (
REM Move all files inside the subdirectory up one level.
move /s %%d\*.* %%d\..\.
REM Delete the directories if they are empty.
RD /y %%d
)
REM Return to your original working directory.
POPD
The above code pushes the current directory name into a stack, and changes dirs to Footage.
Then the For /d command grabs all (if any) of the sub directories of Footage, and feeds them one at a time first into the MOVE command, then into the Remove Directory command.
The MOVE /s command moves all files in directory %%d (including any in sub folders) up one level.
Next the RD /y command automatically deletes the now empty directories, or causes a soft error if they are not empty.
The final command returns the working directory to it's original location, POPing the path off the stack.
On one line, without the PUSHD and POPD commands and the directory cleanup, it looks like this:
Single Line Solution:
For /d %%d in ( *.* ) do move /s %%d\*.* %%d\..\.
Single Line Solution with Cleanup:
To include the cleanup just 'add' the and command && after the move command and before the RD, like so:
For /d %%d in ( *.* ) do ( move /s %%d\*.* %%d\..\. & RD /y %%d )
Why I did what I did.
The fastest way to move a whole bunch of files, is not to tell move how and where to move each file, but to use wild cards that will allow Move to figure out by it'self where to put them. So rather than tell it to move one file at a time, I give it wild cards, which allowsMOVE to work at it's fastest. So I only feed it the individual source and destination directories, and say "copy ALL files from here to there".
A set of brackets (...) can hold, what the interpreter considers a single line of code. Which causes a whole new set of problems, but it allows a special variable like %%d to exist on (what to us appears to be) multiple lines of code. I did that at the top. Later, I used another set of brackets to show the command interpreter what is part of a single line is inside a FOR statement, and what is not.
I also used a bit of old DOS shorthand to specify a parent directory, .. which allows me to not know the exact path of something, and still manipulate things in it's parent . As an example,C:\WINDOWS\.. is C:\, and C:\WINDOWS\SYSTEM32\.. is C:\WINDOWS\ .
You might notice that I also used the file specification . . That is probably unnecessary, but I've ran into enough trouble without it that I use it. It just makes clear to MOVE that we are moving these files to a folder, not a file. And, oh yes, MOVE will gladly move hundreds of your files on top of each other, ruining them all but the last one. You can imagine how I came to embrace the . .
The & allows you to string multiple commands, or programs, onto a single line of code, and allows me to tack the RD to the end of the line, and still have access to the special variables that the FOR command created.
So, now if you were paying attention, you'd have realized that my second sentence was a fib. There is nothing stopping you from tacking a PUSHD & and a & POPD onto the beginning and end of that line.

Deleting folders and subdirectories when a file extension is found in it

I'm new to the board so please go easy! :)
Basically, I'm writing a batch file to delete folders that don't have a file with a certain extension type in them.
so for example if i have the following folder
C:\MUSIC\FLAC\JAZZ\Jazzysong.ape
I need a bit of code that can delete the folder JAZZ because .ape is the wrong file type for the FLAC folder.
Any help would be awesome guys as I've tried variants of findstr, exist and writing to text file and trying to read the path using dir /s /b
I'm lost
I'm still unsure as to which kind of test you want to perform on a directory before deciding to remove it – "whether a certain file type exists" or "whether a certain file type doesn't exist". Your post seems to suggests it is the latter, so it must be the title that is misleading. For the purpose of this answer, I'm assuming that it is indeed the "whether a certain file type doesn't exist" test that you want.
Here's a very simplistic and unassuming approach to the problem:
#ECHO OFF
FOR /D /R "D:\directory_with_flac_files_only" %%D IN (*) DO (
IF NOT EXIST "%%D\*.flac" ECHO RD /S /Q "%%D"
)
That is, just traverse the directory tree and, for every subdirectory, check if it doesn't contain the necessary files. If it doesn't, say goodbye to it. (For safety, I added ECHO before the RD command, so that it does indeed say its goodbye but does not perform the real action, just in case you rush into executing the script without reading further.)
That approach is wrong, however. Even though a directory may not contain the required files, its sub-directories might, and this script does not verify that fact. As a consequence, you might lose some of your invaluable FLAC files. (And I've just saved you the grief.)
So, something more elaborate is needed here. The method I came up with consists in the following steps:
Sort the directories into two categories: those that contain the files with the necessary extension and those that don't.
Process the list of directories that do not contain the files:
1) if a directory is found in the other list, omit it;
2) if it is not found in the other list, remove it.
(In case you are wondering: a directory from the first list may indeed be found in the second list as part of its subdirectory's path.)
I'm far from being convinced that it's the best approach possible, but at least it should work (it did work for me, anyway). Here's my implementation of it:
#ECHO OFF
:: set the params
SET "ext=flac"
SET "rootdir=D:\dir_with_flac_files_only"
SET "todelete=%TEMP%\dirs_to_delete.txt"
SET "topreserve=%TEMP%\dirs_to_preserve.txt"
:: clear the temp lists
TYPE NUL >"%todelete%"
TYPE NUL >"%topreserve%"
:: sort the dirs
FOR /D /R "%rootdir%" %%D IN (*) DO (
IF EXIST "%%D\*.%ext%" (
ECHO %%D>>"%topreserve%"
) ELSE (
ECHO %%D>>"%todelete%"
)
)
:: process the sorted lists
FOR /F "usebackq delims=" %%D IN ("%todelete%") DO (
FIND "%%D" <"%topreserve%" >NUL || ECHO RD /S /Q "%%D" 2>NUL
)
You can still see the ECHO before RD, but consider it just my way of saying, ‘In case I missed something…’. Run the script and look at the output. If it correctly shows only the directories that are due to be deleted, remove ECHO and run the script again to get on with the action.

Resources