Batch file that looks for a folder that contains 1 file - windows

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.

Related

Batch rename: skipping already renamed files

so in one other recent question i needed to find a solution to bulk renaming files by adding .ab into the filename. I succeeded in doing that, but now i face a different problem. Every time i run the batch file, it appends .ab to all the files even those, already renamed. I tried fixing the problem in the following way, which doesn't work.
rem #echo off
FOR /R "C:\Users\" %%G in (*.txt) DO (
%%G|findstr /i /L ".ab">nul
IF errorlevel 1 (
REN "%%G" "%%~nG.ab.txt"
) ELSE (
skip %%G
)
)
pause
Essentially i need to check if the file name already contains ".ab" in its name and then either skip or add .ab depending on the result. I would appreciate any help.
Use a For /F loop, instead of For /R. In addition, instead of using the Dir command with its /S option, (which will output items ending with .txt*), use Where with its /R option instead, (which will output items ending with .txt).
Single line batch-file example, (excludes those basenames ending with, not containing, .ab):
#For /F "Delims=" %%G In ('^""%__AppDir__%where.exe" /R "C:\Users" "*.txt" 2^>NUL^|"%__AppDir__%findstr.exe" /IV "\.ab\.txt$"^"')Do #Ren "%%G" "%%~nG.ab%%~xG"
Don't forget to change C:\Users and/or both instances of .txt and ab as/if necessary.

BATCH Find string in subfolders and move to new location

I'm currently trying to find a string in multiple files.... for example 'Apple' once found i would like to move the files which contain 'Apple' to a new folder.
This is my current script:
findstr /s /m /l /c:"Apple" "C:\Users\User\Desktop\created\*.php"
This finds all of the .php pages which includes the word 'Apple', however it currently lists them, i can't seem to move them into a new location.
I understand i will need to delete "/m" as this prints the file names...
So how do i move them into a new folder?
Thank you
put a for loop around:
for /f "delims=" %%a in ('findstr /smlc:"Apple" "C:\Users\User\Desktop\created\*.php"') do ECHO move "%%~fa" "Z:\New Location\"
Note: this is batch file syntax. For use directly on command line, replace every %% with a single %.
This just echoes the move commands. After troubleshooting, remove the ECHO to arm the move command.
A slightly different alternative, (creates as required a new directory named as the search word, to move it into, and only moves if the file does not already exist in there):
#Echo Off
Set "strPath=%UserProfile%\Desktop\created"
Set "strExtn=.php"
Set "strWord=Apple"
Set "strDest=%UserProfile%\Desktop\test"
CD /D "%strPath%" 2>Nul || Exit /B
For /F "Delims=" %%A In (
'Findstr /MISC:"%strWord%" "%strPath%\*%strExtn%" 2^>Nul'
) Do RoboCopy "%%~dpA." "%strDest%\%strWord%" "%%~nxA" /MOV>Nul
Just modify the values of the variables, lines 2-5, as necessary.

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"

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.

Is There a Way to Delete All Empty Directories in My PC Using Command Line

I want to write a batch file to cleanup my whole C disk by deleting all empty directories in it using command line.
Is it doable?
edited to addapt to comments (filter "problematic" folders) and because that when I was adapting it I realize there is a better solution (old solution still maintained at the end)
#echo off
setlocal enableextensions disabledelayedexpansion
rem Configure where to start searching for empty folders
set "root=c:\"
rem We will use a temp file to store the full list of folders
set "folderList=%temp%\%~nx0.%random%.tmp"
rem Retrieve the full list of folders (except the problematic ones)
rem and store it, sorted, inside the temporary file
( dir /s /b /ad "%root%" ^
| findstr /v /l /i /b /c:"%programFiles:\=\\%" /c:"%systemRoot:\=\\%" ^
| sort /r
) > "%folderList%"
rem Process the temporary file with the list of folders
rem "trying" to remove everything
for /f "usebackq delims=" %%a in ("%folderList%") do (
rd /q "%%~fa" >nul 2>nul && echo "%%~fa" removed
)
rem Remove the temporary file
del /q "%folderList%" >nul 2>nul
To process the full list of folders in a system drive, the list can be huge. And there is a known problem with for /f retrieving data from a running process, so, i have changed the code to use a temporary file. Not as nice but it can be a lot faster.
What will be stored in the temporary file? The full list of folders under the indicated starting point. The list is filtered (findstr) to remove the %programFolders% and %systemRoot% folder from the list. Anything below it will be ignored.
The list is sorted in reverse order. As child folders have as prefix the full parent path, when reverse sorting the list, childs will appear before their parents. If all the childs are removed and the parent becomes empty, it will be also removed.
Once the list is generated, is is readed with a for /f command and a rd command is executed for each of the elements inside it. No check. Just rd. If the folder is not empty it can not be removed, there is no need to check the folder contents.
Once done, the temporary file is removed.
OLD answer. Less code but also less efficient and more complicated. Better use the previous code
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
for /f "delims=" %%a in ('dir /s /b /ad "%root%" ^| sort /r') do (
dir /a /b "%%~fa" 2>nul |(set /p ".=" || echo rd /q "%%~fa" )
)
The for /f command will execute a recursive dir to retrieve the full list of folders under the indicated starting point (change root variable to your needs), and sort this list in reverse order so the folder list can be processed from bottom to root. This step is necessary to ensure that removal of empty childs are executed before processing the parent so if all the descendants where removed the parent will also be removed (if empty, or course)
For each folder found, a dir command is executed and its output piped to a set /p command.
If the dir command generates data (the folder is not empty), the set /p will read information from the pipe and errorlevel will not be set.
But if the folder being processed is empty the dir will generate no output, the set will fail to retrieve data, errorlevel will be set and the rd command will be executed.
Directory removal operations are only echoed to console, if the output is correct, remove the echo

Resources