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

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.

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.

Can someone explain this batch script?

Recently I've been trying to create my own batch commands to make everyday things a lot easier for me. I wanted to create a script that deletes everything within my Temp folder since it is always getting flooded with unnecessary files. I found this code online and it works, but I'm confused on what it's actually meant to do. I understand certain parts of it, but the majority has me confused. I understand it is using a forloop but that doesn't really tell me much. I know logically it makes sense, but I feel like the documentation isn't clear for what the entire script is doing. Anyway, here's the script:
set folder="C:\Users\%USERNAME%\AppData\Local\Temp"
cd /d %folder%
for /F "delims=" %%i in ('dir /b') do (rmdir "%%i" /s/q || del "%%i" /s/q)
Any help would be much appreciated, thanks!
Okay, so the first two lines are very simple. It just sets a variable to a folder path, then CDs into the folder. The /d flag is for changing the drive (C:) if it's currently set to another one.
Now, the last one is a for cycle. What it does is, basically: for each file in dir /b, which shows all files in current directory in bare format (only names), it either executes rmdir, which deletes a directory, or, if rmdir failed because the argument is not a directory, it just dels it. The /s/q stuff in both cases means: /s - delete from all subfolders, /q - do not prompt a Y/N.
Hope I helped!
The first line sets the value of the variable folder.
The second changes the drive and directory to the value assigned to folder.
The third first performs a directory list in basic form (names only) of the current directory (as has just been changed) and assigns each line of the resultant list, in its entirety, to %%i in turn.
The name %%i is then removed using a rmdir or rd command in /q quiet mode and /s including any subdirectories. This works on directories, but not files. The || invokes a del command, again with /s /qwith the same meanings and del deletes files.
hence, any name that is a directory is deleted, and if it's a file, then the rmdir fails and so the del deletes it.
The quotes are to ensure that any name encountered that contains a separator like space or comma is interpreted correctly.

how to move newest file in directory and then process the rest of the script

so i'm trying to take one file at a time out of a directory that contains 2000 files and going up and move it to a different directory to be worked on by the rest of my script. the script is below. Right now i know the gswin64 line works when it is alone and i specify it a filename but not i'm sure with the variable yet. But when i run this it will copy all the files in directory input to directory working before it runs the rest of the script. How do i make it do one at a time then process the script before copying the rest of the files?
for /F "delims=" %%I in ('dir "H:\documents\gs\input\*.*" /A-d /B /O:-D') do (move "H:\documents\gs\input\%%I" "H:\documents\gs\working"&goto filemoved)
:filemoved
Your original code would attempt to execute move "H:\documents\gs\input\*.*" "H:\documents\gs\working" which is why all of th files were moved. What you need to do is execute a directory list command with the switch parameters and supply that to the for /f. This form of dir will show names only. so you need to include the source directory name in the move command. You would also need to have the "delims=" option to ensure that filenames containing separators are processed correctly, and the /a-d directory switch to ensure that directory names are not included. Since you are sorting in reverse-date order, the newest file will be selected first. After the first file is moved, you need to abort the for loop otherwise it will continue processing the entire list, transferring every file. The easy way here is to simply goto a label on the next line.
You've also used a *.* filemask, which will process all files, regardless of extension. Since you appear to want to process only .pdf files, you should probably change that filemask to suit.
for /F "delims=" %%x in ('dir H:\documents\gs\working\*.pdf /b') do set "FileName=%%x"
Again, you need to execute a dir command if you are using a for /f. There's no apparent reason why you wouldn't use the far simpler
for %%x in (H:\documents\gs\working\*.pdf) do set "FileName=%%x"
In either case, you probably want only the name part of the file, so FileName should be set to %%~nx, not %%x.
"C:\program files\gs\gs9.20\bin\gswin64" -o H:\documents\gs\output\"%FileName%" -sDevice=pdfwrite -dFitPage -dFIXEDMEDIA H:\documents\gs\working\"%FileName%"
Unbalanced quotes - the full pathname to the executable needs to be quoted since it contains a separator. Stray spaces after \ will probably need to be removed.
It would be better imho to quote the entire filename, including drive and path rather than filename only.
del /q H:\documents\gs\working\*.*
rm is not a batch command. Note that this command will delete ALL files in H:\documents\gs\working - not just the .pdf files that you appear to be processing.
goto start
The space is required. gotostart is not an inbuilt command.

Command Promp to copy ONLY images from FOLDERS and SUBFOLDERS

I'm wondering if it is possible to set up a batch command to perform this action.
Once .bat file is executed, ALL images from folders and sub-folders would be copied to my location on the desktop.
Example:
Original folder is located:
\intranet\file_location\PP Complete Images (in this folder will be loads of other folders and in those folders there will be .jpg images)
Destination file would be based on the desktop.
So I need to extract .jpg images from all folders and sub-folders.
If image already exists in original folder, skip the image or overwrite as script will be executed every morning.
Or should I look for a software to do this for me?
Existing code:
cd c:
cd\
copy "\\intranet\PP Complete Images\Master Image Folder*.jpg" "C:\Users\username\Desktop\Master Image Folder"
copy "\\intranet\PP Complete Images*.jpg"
exit
How do you want it?
It isn't quite clear to me, how the result exactly should be -- should it be flattened or should it be hierarchical as well?
Look at this for example:
source
folder-1
folder-1-1
image1.jpg
folder-1-2
image2.jpg
cheese.jpg
image3.jpg
some_text.txt
folder-2
folder-2-1
image3.jpg
some_music.mp3
cheese.jpg
target
Should the result be basically a copy of the shown hierarchy (without any other file than the jpgs), or should it be a flattened result like this one:
source
... (see above)
target
image1.jpg
image2.jpg
cheese.jpg
image3.jpg
image3.jpg
How can you do it?
Flattened
You can use DOS' for command to walk directories1 and make a custom function2 to handle the files:
#ECHO OFF
for /r %%f in (*.jpg) do call:copyFile %%f
GOTO END
:copyFile
copy /V /-Y %~1 ..\target
GOTO:EOF
:END
Meaning: for every %%f in the listing of *.jpg from the current working dir, execute function copyFile. The /r switch makes the listing recursing (walk through all subdirectories).
In the function, the argument passed to it (now known as %~1) is passed to the copy function: Copy the file to the target directory which is ..\target in this case. /V lets copy verify the result, /-Y lets it ask for permission to overwrite files. See copy /?!
Very big problem: If you have one or more files in different subfolders of your source directory, which have the same name (like the two cheese.jpgs in my example), you will loose data!
So, I wouldn't recommend this approach, as you risk loosing data (digital cameras are not very creative in naming pictures!).
Hierarchical
Just use robocopy:
robocopy /S <sourcedir> <targetdir> *.jpg
/S creates and copys subfolders as well. You can also use /DCOPY:T to make the directories have the same timestamp than the original ones or /L to preview the actions of robocopy.
Small problem: The /E switch handles subfolders as well, even if they are empty. /S handles subfolders as well, but not, if they are empty. But it handles them, if they are not empty, but have no JPG inside -- so, subfolders without JPGs will result in empty folders in the target folder.
Robocopy has loads of parameters, so check out robocopy /?.
Hope this helps! :-)
1Found here: How to traverse folder tree/subtrees in a windows batch file?
2Found here: http://www.dostips.com/DtTutoFunctions.php
Your existing code:
the cd c: is incorrect. To switch the current drive to c: use
c:
The cd \ is redundant. Your remaining code specifies the directories, so the current directory is irrelevant.
Your first copy command has three problems. Master Image Folder*.jpg means all filenames beginning Master Image Folder and ending .jpg. You probably meant Master Image Folder\*.jpg meaning all files ending .jpg in ...\Master Image Folder\
C:\Users\username\Deskto... is probably an error. It is a literal path, so the actual directory would be C:\Users\username\Deskto... You would probably need C:\Users\%username%\Deskto... to substitute-in the current username.
And then the job would stop on a filename-match, so either you'd be pressing A to overwrite all or you'd be pressing y or n for each name-match.
Your final copy command has no specified destination directory.
You can edit-in your actual code by using the edit button under the original text window, cutting-and-pasting your actual code - censoring if necessary, selecting the resultant code block and pressing the {} button above the edit box which indents each line with the effect of formatting and hilighting the code.
The simplest solution is probably to use
xcopy /d /y /s "\\intranet\PP Complete Images\Master Image Folder\*.jpg" "C:\Users\%username%\Desktop\Master Image Folder\"
which will copy updated files (/d) with automatic overwrite (/y) and scanning subdirectories (/s) from-name/mask to-directory.
This would create an identical directory-hierarchy to the original subtree under the destop's Master Image Folder directory.
You could extend this to
for %%a in (
"\\intranet\PP Complete Images\Master Image Folder"
"\\intranet\wherever\somewhere"
) do xcopy /d /y /s "%~a\*.jpg" "C:\Users\%username%\Desktop\Master Image Folder\"
to perform the same action on multiple directory-subtrees; but you need to ensure that the destination directory is not within any subtree selected for inclusion in the list within the parentheses.
I'd advise against "flattening" the output because if you do that, the latest whatever.jpg from each of the subtrees will end up in your destination directory, without notification that there are many possibly different whatever.jpg versions.
I do believe the solution to your problem would be Robocopy.
Robocopy is just plain awesome!
Here is the syntax of robocopy-
robocopy [Source] [Destination] [File] [...] [options]
Source
Specifies the source folder. Where you want to take the files from.
Destination
Destination directory/folder.
File
Here we are! This is what will help you. Here you can specify an extension you want to move. So in your case, your code would look somewhat like this.
robocopy *.jpg c:\destinationdir /S /MAX:1048576
*To execute this .bat every morning go to a program called task scheduler, dont worry, its built into windows. http://windows.microsoft.com/en-US/windows/schedule-task#1TC=windows-7
*Then Click on Create basic task, and set your task to whenever you like!
Thanks guys for your help!!!
I got it solved and there is a code below if someone would ever need something similar:
pushd Z:\intranet\PP Complete Images\
for /r %%a in (*.jpg) do (
XCOPY /Y "%%a" "C:\Users\username\Desktop\Master Image Folder"
)
popd

Batch file to rename images for WD Live TV

Apologies if this has been answered, the search gives something similar but not exactly what I'm after.
I use XBMC and a Western Digital TV Live as media centers. XBMC uses folder.jpg for movie box art. However, the WD uses both folder.jpg and moviename.jpg.
My folder structure is as follows:
Films\movie1\movie1.mkv(or avi etc...)
Films\movie1\folder.jpg
Films\movie2\movie2.mkv (etc...)
Films\movie2\folder.jpg
What I'm after is a .bat file that will scan the entire films directory, copy the folder.jpg and rename the new jpg using the name of the folder that folder.jpg is in. The original folder.jpg should remain.
Essentially from:
Films\movie1\folder.jpg
To:
Films\movie1\folder.jpg
and
Films\movie1\movie1.jpg
This should happen to each folder in Films.
I'm sure this must be possible but to be honest my knowledge of .bat files is very limited.
You can use a FOR /D loop to iterate over subdirectories of Films:
#ECHO OFF
FOR /D %%I IN ("D:\Path\to\Films\*") DO (
COPY "%%I\folder.jpg" "%%I\%%~nxI.jpg"
)
In the loop, the subdirectory's full path is referenced as %%I and its name alone as %%~nxI (could be just %%~nI if the name never includes a .).
You could run the loop directly from the command prompt, but you'd need to replace the double % characters with single %:
FOR /D %I IN ("D:\Path\to\Films\*") DO COPY "%I\folder.jpg" "%I\%~nxI.jpg"
Please note also that if a moviename.jpg already exists, the COPY command will stop for confirmation of overwriting the file. If you just want to overwrite it anyway without manual confirmation, add the /Y switch:
COPY /Y ...
for /d %%a in (*) do if exist "%%~a\folder.jpg" echo copy /b "%%~a\folder.jpg" "%%~a\%%~na.jpg"
Remove the echo to get it working.

Resources