Batch Script to Find a Folder inside Sub Folders and get Path - windows

I'm trying to get path of a directory containing .snapshot folder. .snapshot should be searched in all parent and sub-directories.
I've a directory structure resembling following tree command output (only more complex, deployment deals a huge NAS drive)
My script, as below, so far lists only one out of potentially 100s of directories containing .snapshot
set Dir=C:\Vol
cd %Dir%
for /d /r "%Dir%" %%a in (*) do if /i "%%~nxa"==".snapshot" set "folderpath=%%a"
echo "%folderpath%"
Output:
C:\Vol\xnd76540\u44753\mike.smith\.snapshot
My Question
How can I check all sub-directories of a folder for .snapshot, come back to the parent and follow another path for again searching .snapshot in other set of sub directories and so on?
Performance tips appreciated.
Couldn't find a more relevant code snippet.

You have it almost done
for /d /r "%Dir%" %%a in (*) do if /i "%%~nxa"==".snapshot" (
echo %%~dpa
)
Or,
for /d /r "%Dir%" %%a in (.snapshot) do if exist "%%~fa" (
echo %%~dpa
)
The problem with the original for in the question is that it is assigning a variable while iterating, and when the for ends, the value echoed is the last assigned as in each iteration the value is overwritten.
Instead, echoing the value inside the running for you will have the full list.

use
set Dir=%1
cd %Dir%
for /d /r "%Dir%" %%a in (*) do if /i "%%~nxa"==".snapshot" set "folderpath=%%a"
echo "%folderpath%"
Save this Batch file say temp.bat
Now in another batch file call it by passing arguments like
temp.bat "C:\Vol1"
temp.bat "another location"

Related

Batch file with a recursive for loop to move file

I am trying to create a batch script to move files base on search criteria into another folder of the same subfolder structure.
I tried the following but the result is not quite right.
for /r "c:\Test_Copy\Source1\" %%x in (Test*.txt) do move "%%x" "c:\Test_Copy\Target1\"
As it is showing
move "c:\Test_Copy\Source1\Sub1\Test1.txt" "c:\Test_Copy\Target1\"
move "c:\Test_Copy\Source1\Sub2\Test1.txt" "c:\Test_Copy\Target1\"
I would like the outcome to be the following.
move "c:\Test_Copy\Source1\Sub1\Test1.txt" "c:\Test_Copy\Target1\Sub1\Test1.txt"
move "c:\Test_Copy\Source1\Sub2\Test1.txt" "c:\Test_Copy\Target1\Sub2\Test1.txt"
How will I be able to achieve this?
Thanks
The for /R loop returns full absolute paths, even the ~-modifiers do not allow to return relative paths. However, you could use xcopy /L, which just lists files that it would copy without the /L option, with paths relative to the source root directory; that list can easily be captured and processed by a for /F loop:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=C:\Test_Copy\Source1"
set "_DESTIN=C:\Test_Copy\Target1"
rem // Change into source root directory:
pushd "%_SOURCE%" && (
rem /* Run `xcopy /L` to list files but not actually copy any, because this returns
rem paths relative to the source root directory; then let `for /F` capture that
rem list, split off the preceding drive letter and skip the summary line: */
for /F "tokens=2 delims=:" %%F in ('
xcopy /L /S /Y "Test*.txt" "%TEMP%"
') do (
rem // Create potentially needed sub-directory, suppress errors when it exists:
2> nul md "%_DESTIN%\%%F\.."
rem // Actually move the currently iterated file into the destination directory:
move "%%F" "%_DESTIN%\%%F"
)
rem // Return from source root directory:
popd
)
endlocal
exit /B
The great advantage of this method is that no string manipulation is involved to derive relative paths, which is dangerous as it could fail in certain situations (for instance, when a root path like D:\ is given, or when a path like D:\some\.\source\dummy\..\folder is specified).
Of course you can also use robocopy /L as suggested in a comment by user Mofi:
robocopy "C:\Test_Copy\Source1" "C:\Test_Copy\Target1" "Test*.txt" /S /MOV /NDL /NJH /NJS
#echo off
for /D /R "c:\Test_Copy\Source1\" %%I in (*)do pushd "%%~I" & (
2>nul >nul mkdir "c:\Test_Copy\Target1\%%~nxI"
move "%%~I\Test*.txt" "c:\Test_Copy\Target1\%%~nxI" & popd
)
Outputs command loop results:
move "c:\Test_Copy\Source1\Sub1\test_001.txt" "c:\Test_Copy\Target1\Sub1\test_001.txt"
move "c:\Test_Copy\Source1\Sub1\test_002.txt" "c:\Test_Copy\Target1\Sub1\test_002.txt"
move "c:\Test_Copy\Source1\Sub1\test_003.txt" "c:\Test_Copy\Target1\Sub1\test_003.txt"
move "c:\Test_Copy\Source1\Sub2\test_001.txt" "c:\Test_Copy\Target1\Sub2\test_001.txt"
move "c:\Test_Copy\Source1\Sub2\test_002.txt" "c:\Test_Copy\Target1\Sub2\test_002.txt"
move "c:\Test_Copy\Source1\Sub2\test_003.txt" "c:\Test_Copy\Target1\Sub2\test_003.txt"
The move command results:
c:\Test_Copy\Source1\Sub1\test_001.txt
c:\Test_Copy\Source1\Sub1\test_002.txt
c:\Test_Copy\Source1\Sub1\test_003.txt
3 file(s) moved.
c:\Test_Copy\Source1\Sub2\test_001.txt
c:\Test_Copy\Source1\Sub2\test_002.txt
c:\Test_Copy\Source1\Sub2\test_003.txt
3 file(s) moved.
Obs.: If all your subfolders c:\Test_Copy\Target1\Sub[n] already exist, remove line 2>nul >nul mkdir "c:\Test_Copy\Target1\%%~nxI"
#echo off
For /D /R "c:\Test_Copy\Source1\" %%I in (*)do pushd "%%~I" & (
move "%%~I\Test*.txt" "c:\Test_Copy\Target1\%%~nxI" & popd
)
Try using for /D /R:
FOR /R - Loop through files (recursively)
FOR /D - Loop through several folders/directories
The option /D /R is undocumented, but can be a useful combination, while it will recurse through all subfolders the wildcard will only match against Folder/Directory names (not filenames)
Source linked to ss64.com
Rem :: Set your folder /Directory /Recursively tree starting at "c:\Test_Copy\Source1"
For /D /R "c:\Test_Copy\Source1"
If you want to do it with batch you need to modify the value of %%x to point to the target directory INSIDE the loop. When you do this you can NOT use % to surround the variables you create inside the for loop - you have to use delayed expansion with ! to surround those variables. Then you can use variable replacement on %%x to change it's value.
Like the comments say, this doesn't work if your directory/file names contain more than one exclamation point.
This does what you want I think:
#echo off
setlocal enabledelayedexpansion
set sourcedir=c:\Test_Copy\Source1\
set targetdir=c:\Test_Copy\Target1\
for /r "%sourcedir%" %%x in (Test*.txt) do (
set sourcefile=%%x
set destfile=!sourcefile:%sourcedir%=%targetdir%!
echo move !sourcefile! !destfile!
)
Just change echo move to move when you are ready to actually do the move.

Symlink all directories whose names contain word (Windows Batch)

I have Directory A, which contains a bunch of subdirectories, and empty Directory B. I would like to create a .bat file that symlinks all of the subdirectories inside Directory A whose names contain "april" (only the top-level ones) into Directory B. Is this possible?
What I have so far is:
echo off
setlocal EnableDelayedExpansion
title Updating Directories...
if exist "C:\path\to\directory\a" (
echo Updating Directories...
set "dira=C:\path\to\directory\a"
set "dirb=C:\path\to\directory\b"
for /f "usebackq delims=|" %%f in (`dir /b "!dira!"`) do (mklink /d "!dirb!\%%f" "!dira!\%%f")
title Symlinks Created^^!
echo Done^^!
pause
) else (
echo Cannot find Parent Directory.
pause
)
This works, but it symlinks all of the subdirectories inside Directory A into Directory B. Is there a way I can, for example, search for top-level directories whose names contain "april," return the list, and then only symlink those?
Not sure why you want a batch file. Just type the command.
for /f "delims=" %A in ('dir /b /ad "%userprofile%\desktop\*u*.*"') Do mklink /d "%userprofile%\desktop\b\%~nxA" "%A%
This create a link in a folder called B on the desktop (so create it first) for any folder on the desktop that contains the letter u in the name. See dir /?.
Note in Windows (NT family) the wildcard operators are regular expressions unlike Dos.
?*net*.* shows all files that contain net, but don't begin with net.
Thanks to #CatCat I was able to figure it out. Here's what's now working, for posterity's sake:
echo off
setlocal EnableDelayedExpansion
title Updating Directories...
if exist "!userprofile!\path\to\directory\a" (
echo Updating Directories...
set "dira=!userprofile!\path\to\directory\a"
set "dirb=!userprofile!\path\to\directory\b"
for /f "usebackq delims=|" %%f in (`dir /b "!dira!\*april*.*"`) do (mklink /d "!dirb!\%%f" "!dira!\%%f")
title Symlinks Created^^!
echo Done^^!
pause
) else (
echo Cannot find Parent Directory.
pause
)

Batch file that looks for a folder that contains 1 file

i have a lot of folders with a random number of files within.
And the most of them just have 1 file inside it, these files needs to move to the parent folder. but i don't know how i should do it with a batch file.
I use Windows 7 Ultimate
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /d /r "%sourcedir%" %%a IN (*) DO (
FOR /f %%c IN ('dir /b/a-d "%%a\*.*" 2^>nul ^|find /c /v ""') DO IF %%c==1 ECHO(MOVE "%%a\*.*" "%%a\..\"
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The for /d /r finds all of the subdirectory names starting at sourcedir and assigns thenm to %%a in turn.
Each directory is then examined for filenames only; the 2>nul suppresses error messages for empty directories, and the output of the dir command is fed to find which counts (/c) the number of lines which don't match "" (ie. counts the lines of directory = # files returned). This is applied to %%c
If %%c is 1, then move all (one) files from the directory to its parent.
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
This solution don't use any external .exe command, so it should run faster. Also, it is clear enough to be understood with no problems, I think...
#echo off
setlocal EnableDelayedExpansion
for /D %%d in (*) do (
set "firstFile="
set "moreThanOneFile="
for %%f in ("%%d\*.*") do (
if not defined firstFile (
set "firstFile=%%f"
) else (
set "moreThanOneFile=true"
)
)
if not defined moreThanOneFile move "!firstFile!" "%%d"
)
You have a number of folders that all may or may not contain files within them, and you want to move all files to some other directory?
PowerShell is the new and improved super charged version of using a batch file, and this is how you'll do it.
Run PowerShell
paste in the following
dir -Recurse C:\FolderContainingManySubfolder | ? PSIsContainer | dir -Recurse | move-item -Destination T:\somePath -WhatIf
Replace C:\FolderContainingManySubfolder with the folder that has all of those other folders with one or two items each, and replace T:\somePath with the place you want the single files to go.
Run it, and you'll see a lot of 'What If' output, which shows you what would happen if you were to run the command. If you're happy with what you see, then remove the -WhatIf parameter from the end.

How to copy a file to many directories using prompt?

I need to copy a file and paste it in many directories, can I do this with a single command in windows prompt?
I tried this code, but it didn't work:
> copy C:\main\folder-1\docs\file.txt C:\main\*\docs
The names are illustratives, but the idea is: inside the "main" folder I have 50 folders ("folder-1", "folder-2", ..., "folder-50")... and inside each "folder-N", I have other folder named "docs". Every time that I create a file into any "folder-N\docs" I need to paste it into all "folder-N\docs".
Is it possible? or I really need to paste the file, folder by folder?
Straight up from the command line:
for /D %x in (c:\main\*.*) DO COPY c:\main\folder-1\docs\file.txt %x\docs\file.txt
From a BAT file or CMD file (not from the command line), you need to escape the % variable again
for /D %%x in (c:\main\*.*) DO COPY c:\main\folder-1\docs\file.txt %%x\docs\file.txt
Of course, if the subdirectory "docs" directory doesn't exist in each subfolder of "main", the iteration will print an error. That's why in my example above I explicitly specify copying to %x\docs\file.txt. If I had just said `%x\docs" as the target of the copy, it might create a file called "docs" that contains the contents of the file.txt source.
More information on for loops here and here:
Or just type "help for" at the command prompt.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir\one"
:: Build list of directorynames
SET "dnames="
FOR /f "delims=" %%a IN ('dir /b /ad "%sourcedir%" ') DO (
IF EXIST "%sourcedir%\%%a\docs\" SET "dnames=!dnames! "%%a""
)
FOR %%a IN (%dnames%) DO FOR %%b IN (%dnames%) DO IF NOT %%a==%%b (
FOR %%s IN ("%sourcedir%\%%~a\docs\*") DO (
IF NOT EXIST "%sourcedir%\%%~b\docs\%%~nxs" ECHO(COPY "%sourcedir%\%%~a\docs\%%~nxs" "%sourcedir%\%%~b\docs\%%~nxs"
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The required COPY commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(COPY to COPY to actually copy the files.
I'd suggest that you create a testing subtree of a few small subdirectories before releasing in anger. Remember that this "report" may say to copy the same file from dir1 and dir5 into dir3 but when released because the file would actually be copied from dir1 to dir3, the copy from dir5 would not occur (when the copy from dir5 is checked, the copy from dir1 would already have occurred.)
You could suppress the copy report by appending >nul to the copy line.
Note that this routine is oriented towards one-file-at-a-time and showing what should be done. This following routine should do the same thing, is shorter but doesn't provide an elegant testing structure:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir\one"
:: Build list of directorynames
SET "dnames="
FOR /f "delims=" %%a IN ('dir /b /ad "%sourcedir%" ') DO (
IF EXIST "%sourcedir%\%%a\docs\" SET "dnames=!dnames! "%%a""
)
FOR %%a IN (%dnames%) DO FOR %%b IN (%dnames%) DO IF NOT %%a==%%b (
ECHO(xcopy /d "%sourcedir%\%%~a\docs\*" "%sourcedir%\%%~b\docs\"
)
GOTO :EOF
Again, the xcopy is reported, not executed for testing purposes.

How do I iterate over a set of folders in Windows Shell?

I'm currently trying to write a .cmd Windows Shell script that would iterate over a set of folders. However even the following simplest script:
echo "%ROOT%"
for %%f in ("%ROOT%\Binaries\" ) do (
echo "%%f"
if not exist "%%f\Subfolder"
md "%%f\Subfolder"
)
outputs:
CurrentDir>echo "<ActualPathToRoot>"
"<ActualPathToRoot>"
%f\Subfolder was unexpected at this time
CurrentDir>if exists "%f\Subfolder"
What am I doing wrong? How do I alter that script so that it iterates over that one folder and once it see there's no subfolder named "Subfolder" it creates that subfolder? Also is there a good tutorial on writing such scripts?
For (sub)folder-iteration you need to use a different for parameter.
So if you want to list all directories of C: you should do this:
for /d %%A in (C:\*) do echo %%A
Note the parameter /d which indicates a directory. To go into subdirectories you need to do a recursive for with /r
for /r C:\Windows %%A in (*.jpg) do echo %%A
This would iterate through all Windows subdirectories looking for JPGs. Low behold you should be able to do /d /r and this reference suggests you can - I simply can't, but maybe you are able to do this?
A workaround I quickly jotted down is to just do a dir of all directories in a for loop:
for /f "delims=" %%A in ('dir /ad/s/b') do echo %%A
Note that dir is used in conjunction with /ad/s/b which performs a recursive listing of directories, printing the names of the directories found.
With these tools in your hand you should be able to do your if-subfolder construct. Note that you might need
This works for me:
echo %ROOT%
for /D %%f in (%ROOT%\Binaries\*) do echo %%f && if not exist %%f\Subfolder md %%f\Subfolder

Resources