cmd or powershell to get all subdirectories - windows

I'm trying to figure out what cmd or powershell command I can use to get the subdirectories contained in a directory. I only want the last subdirectory in each listed, oo for example if I have something like:
matthew\folder1\folder2\folder3
and
matthew\folder6\folder7\folder8
and I am in the "matthew" directory, I just want to return the list that has:
folder1\folder2\folder3
folder6\folder7\folder8
I try to use dir /b /s but it gives me something like:
folder1
folder1\folder2
folder1\folder2\folder3
folder6
.
.
.
Any help would be greatly appreciated.

Still having difficulty understanding what you're looking for.
You want a list of all folders below the current folder which do not have any child folders. Additionally, you only want to display the portion of the path which is not specified by the current path.
For a Powershell answer:
Get-ChildItem -Directory -Recurse | Where-Object {
(Get-ChildItem $_.FullName -Directory).Count -eq 0;
} | ForEach-Object {
Write-Output $_.FullName.SubString((Get-Location).Path.Length);
}
Note the -Directory switch requires Powershell 3.0, if I remember right.

edited to reduce processing time
#echo off
setlocal enableextensions disabledelayedexpansion
subst :: .
for /r "::\" %%a in (.) do (
set "leaf=1"
for /d %%b in ("%%~fa\*") do if defined leaf set "leaf="
if defined leaf for /f "tokens=* delims=:\" %%b in ("%%~fa") do echo %%b
)
subst :: /d
There are two problems: determine what folders to show and remove the prefix from the output.
To solve the first problem, the folder structure under the current folder is enumerated and for each folder found it is tested if there is a folder inside. In there are no child folders, the current folder needs to be echoed.
To solve the second problem, all the operations are done under a subst drive. The current folder is defined as the root of the :: drive. That way, the full path to the current folder is removed from the string to output, replaced by a simple ::\, that will be removed with a properly configured for /f command when the folder must be echoed.

#ECHO OFF
SETLOCAL
:: Display leaves-only
SET "sourcedir=U:\sourcedir"
FOR /r "%sourcedir%" /d %%a IN (*) DO (
SET "flag=Y"
FOR /d %%b IN ("%%a\*") DO SET "flag="
IF DEFINED flag ECHO %%a
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
This worked for me.

Related

Moving specific extension up one directory level

My current folder structure goes as follows:
E:\Videos\Movies\Random Folder Name\Subs\Random File Name.srt
I would like to move my .srt files up one level so it reads:
E:\Videos\Movies\Random Folder Name\Random File Name.srt
I would prefer this to be a .bat file, but am willing to use PowerShell.
~EDIT~
I found something online that partially works and edited it to my needs:
#echo off
set thisdir=%cd%
for /f "delims=" %%A in ('dir /b /ad') do (
cd /d "%%~dpnA"
for /f "delims=" %%B in ('dir /b /ad') do (
echo Level 2 Directory: %%~dpnB
cd /d "%%~dpnB"
for /f "delims=" %%C in ('dir /b /ad') do (
echo Level 3 Directory: %%~dpnC
cd /d "%%~dpnC"
move *.srt ..\
cd..
rd "%%~dpnC"
)
)
)
This works, but only for the first folder, I can't seem to make Level 2 recursive as that is the level with random movie names. I tried replace for /f with for /r, but it was a no go.
Here's a one-liner:
forfiles /m *.srt /s /c "cmd /c move #file .."
Full code (you can run this from any drive now):
#echo off
cd /d E:\Videos\Movies\
for /r %%i in (*.srt) do move "%%~dpnxi" "%%~dpi.."
pause
This looks for all files with type .srt and moves them to the folder it was found in -1 directory (%%~dpi is the directory it was found in, adding .. to a path removes the last directory, so C:\Users\.. would put you at C:\).
PS: This time I have tested this, and it works.
Although the answers already given work, I still wanted to try and figure out how to perfect the code to my exact needs. Couldn't accomplish this with CMD, so I looked into powershell (which was easier for me to grasp for some reason) and coded this:
$sourcefolder = "F:\Videos\Movies\*\Subs\"
$files = Get-ChildItem -Recurse $sourcefolder | where {$_.PSIScontainer -eq $false}
foreach ($file in $files)
{
$destinationFolder = Split-Path -Parent $file.Directory.FullName
move-item $file.FullName $destinationFolder
}
It doesn't specify .srt files, but they are the only extension located in that folder. Thank you for the help guys!

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

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"

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.

Comparing Two Folders and its Subfolder batch file

I have two folders that contain all the same files and subfolders, but the conents inside each file may have changed. I want to write a batch file that will search through each file and look for any differences. What's the best tool for what I want to do?
No need for a batch file. A single FC command can do what you want:
fc folder1\* folder2\*
You can be more specific for the file mask in the first folder if you want. For example folder1\*.txt.
The command will report on files that exist in folder1 but are missing in folder2. Extra files in folder2 are simply ignored.
There are a number of options to the FC command. Enter HELP FC or FC /? from the command prompt to get more information.
EDIT
Extending the solution to support subfolders is a bit tricky. It is easy to iterate the folder hierarchy for a given root using FOR /R. The problem is getting the relative paths so that the hierarchy can be applied to another root.
The simplest solution is to use FORFILES instead, since it directly supports relative paths. but FORFILES is... S L O W :/
At this point, a batch file makes sense:
#echo off
setlocal
set "folder1=c:\path\To\Folder1\Root"
set "folder2=d:\path\To\Folder2\Root"
set "fileMask=*"
for /f "delims=" %%F in (
'echo "."^&forfiles /s /p "%folder1%" /m "%fileMask%" /c "cmd /c if #isdir==TRUE echo #relpath"'
) do fc "%folder1%\%%~F\%fileMask%" "%folder2%\%%~F\*"
Here is another way to accomplish the task. Set the variables Folder1 and Folder2 to the full path of the folders you want to compare and run the batch file.
Output:
Dup – the file exists in both folders and are identical.
Dif - the file exists in both folders but the content of the files are different.
New – The file exists in one folder but not the other.
#Echo Off
SetLocal EnableDelayedExpansion
Set "Folder1=%UserProfile%\Desktop\Test Folder1"
Set "Folder2=%UserProfile%\Desktop\Test Folder2"
For /R "%Folder1%" %%x In (*.*) Do (
Set "FullPath=%%x"
Set "RelPath=!FullPath:%Folder1%=!"
If Exist "%Folder2%!RelPath!" (
>Nul 2>&1 FC /b "%Folder1%!RelPath!" "%Folder2%!RelPath!" && (
Echo Dup - %%x
)||(
Echo Dif - %%x
)
) Else (
Echo New - %%x
)
)
For /R "%Folder2%" %%x In (*.*) Do (
Set "FullPath=%%x"
Set "RelPath=!FullPath:%Folder2%=!"
If Not Exist "%Folder1%!RelPath!" (
Echo New - %%x
)
)
I'm having better luck with the following batch file. The path names have to completely match though; so only the Drive Letter differs.
Mapping a shared network folder may make this easier. I can't say for sure for your case.
'---
setlocal
set "folder1=D:\User\Public"
set "Drv2=E:"
set "fileMask=*"
setlocal
set "folder1=<DrvLttr>:\<Folder>\<SubFolder>"
set "Drv2=<DrvLttr2>:"
set "LogFile=<SystemDrv>\User\<UserName>\<LogFileName>"
ECHO "the '>' may OVER WRITE or make a ~NEW~ File for the results" > "%LogFile%"
ECHO " '>>' adds to the end of the file >> "%LogFile%"
FOR /R %folder1% %%A in ( *.* ) DO FC "%%A" "%Drv2%%%~pnxA" 1>> "%LogFile%" 2>&1
If you wish to note what is going to be the command for testing, you can try inserting ECHO after DO. You can drop the 1>>... stuff to see the result on screen, instead of having to open the output file.
I modified a batch file I wrote for a CD process that should meet your need. It
takes 2 directory trees and compares each file in each tree
creates a list of the file differences (named File_differences.txt in the output folder)
and creates a folder with a diff file for each non-matching object
If both directory structures are under the same parent, then all you need to do is update the first 8 variables in the script. If the directory trees have different parents, then read through the scripts comments. Particularly lines 14, 38 and 46.
:: This script compares the contents of 2 trees
:: set a workspace location for the script outside of the trees being reviewed
set home=D:\path\to\batch_file_home
set Input=D:\path\to\batch_file_home\Input_Files
set Resource=D:\path\to\batch_file_home\Resource_Files
set Output=D:\path\to\where your want to view your\Output_Files
set environment=D:\path\to\parent directory containing the different tree structures (if they do not share a parent, then make this the drive)
:: the next 3 lines are only needed if you want to predefine multiple directories for comparison
set Prod=production
set QA=test
set Dev=branches\dev
:: If you remove the 3 lines above, then you need to replace the 2 below variables with values
:: If the trees are not under the same parent, then include the full path for Tree A and B below
set Tree_A=%Prod%
set Tree_B=%QA%
:: if you already have an object list, place it in the Input folder and remove lines 24 through 35 of this script
set Object_List=Object_List_minus_Direcotries.txt
set Output_File=File_differences.txt
if exist %Output%\%Output_File% del %Output%\%Output_File%
if exist %Output%\Differences\*.txt del %Output%\Differences\*.txt
if exist %Resource%\* del /q %Resource%\*
:: since you state the objects in both trees are always the same, I have not included a comparison to verify the 2 trees match
:: this section identifies the contents of Tree A
cd %environment%\%Tree_A%
dir /b /s > %Resource%\Complete_Tree_A_Object_List.txt
:: Next, remove the objects that are directories
setlocal enabledelayedexpansion
for /f "tokens=*" %%p in (%Resource%\Complete_Tree_A_Object_List.txt) do (
dir /a:d /b %%p 2>nul >nul && (set object_type=folder) || (set object_type=file)
echo !object_type!
if !object_type!==file echo %%p >> %Resource%\%Object_List%
)
:: in the object list, remove the parent tree from the path
:: if the Trees are not under the same parent, then comment out the below 6 lines
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '\\','/' | set-content %Resource%\%Object_List%"
powershell -command "(get-content %Resource%\%Object_List%) | Foreach {$_.TrimEnd()} | Set-Content %Resource%\%Object_List%"
set remove_parent_prefix=%environment%\%Tree_A%
set remove_parent_prefix=%remove_parent_prefix:\=/%
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '%remove_parent_prefix%/','' | set-content %Resource%\%Object_List%"
powershell -command "(Get-Content %Resource%\%Object_List%) -replace '/','\' | set-content %Resource%\%Object_List%"
:: the below loop assumes both Trees are under the same parent. If this is not the case, replace the cd %environment% line with cd %home%
:: when the Trees are not under the same parent, set home to the root location, example cd D:\
setlocal enabledelayedexpansion
for /f "tokens=*" %%x in (%Resource%\%Object_List%) do (
set Diff_File=%%x
set Diff_File=!Diff_File:\=-!
cd %environment%
fc %Tree_A%\%%x %Tree_B%\%%x > "%Output%\Differences\!Diff_File!-%Output_File%"
for %%a in ("%Output%\Differences\!Diff_File!-%Output_File%") do for /f %%b in ('find /c /v "" ^< "%%a" ') do if %%b LSS 3 del "%%a"
for %%R in ("%Output%\Differences\!Diff_File!-%Output_File%") do if not %%~zR lss 1 (
echo %%x >> %Output%\%Output_File%
)
for %%R in ("%Output%\Differences\!Diff_File!-%Output_File%") do if %%~zR lss 1 (
del "%Output%\Differences\!Diff_File!-%Output_File%"
)
)
endlocal
:: Clean up Resources. If you want to review the temp files used to create the report, comment out the below line
if exist %Resource%\* del /q %Resource%\*

How to grab the names of all sub-folders in a batch script?

I just want to know how can I get all the names of the folders in a current directory. For example in my current directory I have three folders:
stackoverflow
reddit
codinghorror
Then when I execute my batch script all the three folders will print in the screen.
How can I achieve this?
Using batch files:
for /d %%d in (*.*) do echo %%d
If you want to test that on the command line, use only one % sign in both cases.
On Windows, you can use:
dir /ad /b
/ad will get you the directories only
/b will present it in 'bare' format
EDIT (reply to comment):
If you want to iterate over these directories and do something with them, use a for command:
for /F "delims=" %%a in ('dir /ad /b') do (
echo %%a
)
note the double % - this is for use in a batch, if you use for on the command line, use a single %.
added the resetting of default space delims in response to #Helen's comment
With PowerShell:
gci | ? { $_.PSIsContainer }
Old Answer:
With PowerShell:
gci | ? {$_.Length -eq $null } | % { $_.Name }
You can use the result as an array in a script, and then foreach trough it, or whatever you want to do...
For getting all the subfolders of a specific directory and display it in CMD :
#echo off
dir C:\input /s /b /o:n /a:d
Pause&Exit
For getting all the subfolders of a specific directory and save it in a text file :
dir C:\your_directory /s /b /o:n /a:d > output.txt

Resources