Iterate Directories with Batch - batch-file

The objective is to display the directory name in MYFOLDER.
MY.exe exists in the folder, but curiously, without the wildcard in ...\desktemp*, the "#echo Showing subfolders" is never displayed, but "#echo G is working" is. However MY.exe is never found when moved to one of the subfolders.
OTOH the current code never finds MY.exe and never displays "#echo G is working" but properly lists each subfolder: "#echo Showing subfolders".
The other problem is the pauses at the end of the block are never reached.
Substituting the inner For with
cd \Users\%USERNAME%\Desktop
for /D /r %%G in ("desktemp*") do (
gets essentially the same result. My.exe isn't found if moved to one of the subfolders of desktemp.
Setlocal EnableDelayedExpansion
set CURRDRIVE=C
SET MYFOLDER=
:SEARCHDRIVES
REM BLOCK
for %%B in (C) do (
if exist %%B: (
PUSHD %%B:\
if NOT DEFINED MYFOLDER (
ECHO "%CD%"
REM This always displays path batch is run from.
REM The above Pushd doesn't change to C:\
for /f "tokens=*" %%G in ('dir /b /s /a:d "%%B:\Users\%USERNAME%\Desktop\desktemp*" ^| find "\"') do (
#echo Showing subfolders
#echo %%G
pause
if exist "%%G\MY.exe" (
call set MYFOLDER=%%G
#echo %%G
#echo G is working
call echo %MYFOLDER%
pause
GOTO GOTMYFOLDER
)
)
)
)
REM Exist Drive
)
REM Drives Loop
:GOTMYFOLDER
cd /d %CURRDRIVE%:\
echo %MYFOLDER%
cd %MYFOLDER%
pause
The above is a chunk whittled from a larger code block: the ultimate aim will be to get the folder names"\Users\New\Desktop\desktemp" into a variable via prompt.
Are the Escape Characters, Delimiters and Quotes in the nested blocks implemented properly?

The answer escaped this poor little brain until it cottoned on to what the "DIR" and "For /D /R" were really up to. What was sought for was in the addition of a new "For /D" (no /R).
This first (extra) "For /D" determines the folder names to iterate from.
(Specifically anything but the Windows directory where we run into problems with >260 filenames.)
This locates the MY.exe file somewhere in the Users folder (more precisely in any root folder beginning with U):
Setlocal EnableDelayedExpansion
set CURRDRIVE=C
SET MYFOLDER=
:SEARCHDRIVES
REM BLOCK
for %%B in (C) do (
if exist %%B: (
PUSHD %%B:\
if NOT DEFINED MYFOLDER (
ECHO "%CD%"
REM This always displays path batch is run from.
REM The above Pushd doesn't change to C:\
for /D %%Z in (U*) do (
cd \%%Z
for /D /r %%G in ("*") do (
if exist "%%G\MY.exe" (
call set MYFOLDER=%%G
#echo %%G
#echo G is working
call echo %MYFOLDER%
pause
GOTO GOTMYFOLDER
)
)
)
)
)
REM Exist Drive
)
REM Drives Loop
:GOTMYFOLDER
cd /d %CURRDRIVE%:\
echo %MYFOLDER%
cd %MYFOLDER%
pause
Edit:
The source of the error spam in the comment below is this command:
Insert batch code to elevate UAC privileges [code][1] from TanisDL
Setlocal EnableDelayedExpansion & pushd "%CD%" & CD /D "%~dp0"
set CURRDRIVE=C
FOR /F "usebackq delims==" %%G IN (dir %CURRDRIVE%:\ /A:D /O:G /S /B ^| FIND /I "myString") DO (set "foundMyString=%%~pG")

Related

Batch file to create folder and move file in the folder

I am in the middle of batch extracting screenshots for contents we are planning to use on a tube site I am working on.
The jpeg files per content is labled as followed:
6c82c0239f6eb839-1
6c82c0239f6eb839-2
all the way to 120
The file name is different per content
a82384e2c46ba4af-1
a82384e2c46ba4af-2
etc.
They will all be extracted to a singe folder.
So I basically need a batch file that will create folders based on the content name without the dash and number and move all 120 jpegs in the folder with the content name.
For example:
Create folder named 6c82c0239f6eb839 and
move 6c82c0239f6eb839-1 to 6c82c0239f6eb839-120 in to the created folder.
I saw another thread with the following batch file. its pretty much what I want but the folder name is only 3 characters long and the files are copied to the newly created folders instead of moving them.
#echo off
SetLocal EnableDelayedExpansion
for /F "delims=" %%a in ('dir /b *.jpeg') do (
set Name=%%a
set Folder=!Name:~0,3!
xcopy /y "%%a" !Folder!\
)
Could someone change this so that it will display full file name without the dash and number for the folders and move files in its respective folders instead of copy?
Thank you
#echo off
setlocal
#rem Get each jpeg file.
for /F "delims=" %%A in ('2^>nul dir /b *.jpeg') do (
rem Get filename as token before the dash.
for /f "delims=-" %%B in ("%%~A") do (
rem Make dir if needed.
if not exist "%%~B" md "%%~B"
rem Check if isdir.
2>nul pushd "%%~B" && popd
if errorlevel 1 (
>&2 echo Failed isdir "%%~B".
) else (
rem Do the move operation.
>nul move /y "%%~A" "%%~B"
if errorlevel 1 (
>&2 echo Failed move "%%~A" to "%%~B"
)
)
)
)
exit /b %errorlevel%
The code is well remarked so if you want to understand
the evaluated code by changing #echo off to #echo on.
The use of %errorlevel% after the exit /b is not
required though will let you know what the errorlevel is
when #echo on is used.
The pushd tests for a directory
(even if it is a symlink).
errorlevel is checked to decide if to echo a
error message or do the move.
As the for loop variables are used direct, use of
enabledelayedexpansion is not needed.
Many commands support the argument of /? to get help
about the command. i.e. move /?.
If you only try to copy the correct jpeg to the correct folder, you can do this:
#echo off
SetLocal EnableDelayedExpansion
CD <CORRECT ROOT PATH>
for /F "delims=" %%a in ('dir /b *.jpeg') do (
set Name=%%a
REM I presume all the files have 16 characters before the dash
set Folder=!Name:~0,16!
IF NOT EXIST !Folder! MKDIR !FOLDER!
xcopy /y "%%a" !Folder!\
)
I was not able to test.
First of all, I would like to apologize for my manners regarding my initial post.
The answer by micheal_heath has resolved my issue.
Furthermore, I happened to find this post by user Salmon Trout from a different site which also worked.
Batch file to make folders with part of file name and then copy files
#echo off
setlocal enabledelayedexpansion
for %%A in (*.psd *.jpg) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1* delims=_" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
pause
I just changed the the following line remove the hypen and numbers to create folders for the file name properly.
for /f "tokens=1* delims=-***" %%D in ("!fname!") do set folname=%%D
I still lack the knowledge on why and how both methods work, but this has been an interesting start for me. I hope other beginners trying to solve a similar issue can find something useful from this post.

Batch script - Quick recursive find of first folder starting from a root location

I want to make a script which finds as quickly as possible first folder named Target starting from root location D:\ and return its absolute path.
Folder structure of root location (D:\) can be like this:
-DontSearchHereFolder
-Folder1\Subfolder1\SSubfolder1\SSSubfolder1\
-Folder2\Subfolder2\SSubfolder2\TargetFolder
-DontSearchHereFolder2
-Folder3\Subfolder3\
Output of the script should be: D:\Folder2\Subfolder2\SSubfolder2\TargetFolder
For now I tried 2 methods but it's not quick enough:
(1)
set TG=\TargetFolder
set root=D:\
cd %root%
for /f "delims=" %%a in ('dir /b /s /a:d "%root%" ^|findstr /e /i "%TG%"') do set "folderpath=%%~a"
(2)
for /d /r "%root%" %%a in (*) do if /i "%%~nxa"=="%TG%" set "folderpath=%%a"
(1) is quicker than (2)
Question1: Is it possible to specify in command to search only for a maximum of 2 folders "down" from root (e.g. D:\Folder1\Subfolder1) ?
Question2: Is it possible to specify folders that should be automatically skipped (e.g. DontSearchHereFolder1&2)
This batch code is exactly for what you have asked for optimized for speed. It ignores the two specified directories on first level and it searches for the folders maximal two folder levels deep.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "Root=D:"
set "TG=TargetFolder"
set "Ignore1=DontSearchHereFolder"
set "Ignore2=DontSearchHereFolder2"
for /D %%A in ("%Root%\*") do (
if "%%~nxA" == "%TG%" set "FolderPath=%%A" & goto Found
if not "%%~nxA" == "%Ignore1%" (
if not "%%~nxA" == "%Ignore2%" (
for /D %%B in ("%%A\*") do (
if "%%~nxB" == "%TG%" set "FolderPath=%%B" & goto Found
for /D %%C in ("%%B\*") do if "%%~nxC" == "%TG%" set "FolderPath=%%C" & goto Found
)
)
)
)
echo Could not find folder: "%TG%"
goto EndSearch
:Found
echo Found folder: "%FolderPath%"
:EndSearch
endlocal
The string comparisons are done case-sensitive for maximum speed.
No recursive subroutine calls are used as usually would be done for such tasks for maximum speed.
The comparisons for the directories to ignore in root folder are coded in batch script directly not using an array or a list of folder names for maximum speed.
Delayed expansion is not used for faster processing the command lines.
But much faster would be coding an executable in C/C++/C# for that task as processing the command lines of the batch file takes most likely the most time on searching for the folder.
Note: Command FOR ignores folders with hidden attribute set.
Well, I use for such tasks shareware tool Total Commander which supports searching only in selected folders for a specific folder not more than X levels deep extremely fast.
This should take into account all the limits indicated in the question, but unless a lot of folders are found inside the indicated exclusions, I don't think this should be faster, just give it a try
#echo off
setlocal enableextensions disabledelayedexpansion
set "source=d:\"
set "target=TargetFolder"
set "maxLevels=2"
set excludeFolders= "DontSearchHereFolder" "DontSearchHereFolder2"
for %%s in ("%source%") do for /f "tokens=*" %%f in ('
robocopy "%%~fs." "%%~fs." /l /nfl /njh /njs /nc /ns /s
/xd %excludeFolders% /lev:%maxLevels%
^| findstr /e /i /l /c:"\\%target%\\"
^| cmd /v /q /c"set /p .= &&(echo(!.!)"
') do echo "%%~f"
I think this is the fastest possible way to do this:
#echo off
setlocal EnableDelayedExpansion
if "%1" neq "" goto %1
set "root=D:\"
set "TG=TargetFolder"
set "exclude=/DontSearchHereFolder1/DontSearchHereFolder2/"
"%~F0" Input | "%~F0" Output > result.txt
set /P "folderpath=" < result.txt
del result.txt
echo First folder: %folderpath%
goto :EOF
:Input
cd "%root%"
for /D %%a in (*) do if "!exclude:/%%a/=!" equ "%exclude%" (
cd "%%a"
dir /B /S /A:D "%TG%" 2>NUL
cd ..
)
exit /B
:Output
set /P "folder="
echo "%folder%"
set "i=0"
for /F "tokens=2" %%a in ('tasklist /FI "IMAGENAME eq cmd.exe" /FO TABLE /NH') do (
set /A i+=1
if !i! equ 2 taskkill /PID %%a /F
)
exit /B
The folders to exclude are given in a slash-separated list; if this list is longer, the process run faster because more folders are skipped. The target folder is search in each one of the non-excluded folders via a dir /B /S /AD "%TG%" command, that is faster than any combination of other commands. The process ends as soon as the first folder name is received in the rigt side of the pipe; the remaining processing at left side of the pipe is cancelled via a taskkill command.

how to change directories automatically after dir (a file /s /p) in batch cmd?

Im making a small script but i reached a head scratch
I want the batch file to look for example.exe or Folder name in all drives then cd to it and create a txt file inside it? is that even possible :P?
cd /d D:
dir example.exe /s /p
lets say its found and the dir is D:/Example.exe
so i want the batch to do this,
if example.exe is found cd to it directory then
REM. >> "D:/logs.txt
is that possible? –
what do i put after "if exist" for the batch file to automatically switch to the found file directory
#echo on
cd /d D:
dir example.exe /s /p if exist (whether its in D:/Folder/folder or D:/Folder go to directory)
echo >test.txt
pause
Finally Solution by #Stephan best working answer
#echo off
setlocal enabledelayedexpansion
for /f "delims=:" %%a in ('wmic logicaldisk where "size>0" get caption^|find ":"') do (
for /f "delims=" %%A in ('dir /s /b %%a:\example.exe 2^>nul') do (
ECHO break>"%%~dpAtest.txt"
)
)
To catch the output of a command, use for.
dir /p does not make sense here (it's to pause if the output is longer than the screen). You want /b (bare format; filename only / drive/path/filename when used with /s).
%%~dpA gives drive:\path\ only.
break>filename to create an empty file (REM. does also work, but I prefer break)
#echo off
setlocal enabledelayedexpansion
for /f "delims=:" %%a in ('wmic logicaldisk where "size>0" get caption^|find ":"') do (
for /f "delims=" %%A in ('dir /s /b %%a:\example.exe 2^>nul') do (
ECHO break>"%%~dpAtest.txt"
)
)
this puts an empty test.txt to every folder in every available drive where there is an example.exe. If there already should be a test.txt, it gets overwritten by an empty file.
NOTE: this only echoes the break command to the screen (for security reason). If the output is like you want it, remove the ECHO.
Updated answer, since I got your question after this update:
In order to process all the files you found:
FOR /F "delims=#" %%f IN ('dir example.exe /s /b ') DO (
echo example.exe was found at path %%~pf
)
Now you can modify your ECHO statement:
ECHO some text > C:\logs.txt
If you want to append to the file instead of replacing, you have to use two brackets:
ECHO some text >> C:\logs.txt
You can enter a path after > . You don't need to CD before.
You can also use the variable for CD:
cd %%~pf
If you want some other part of %%f, you can do FOR /? on your command line or see the reference

Batch file that creates folder with wildcard in path

I want to write a batch file that creates a folder (if it does not exist) and copies a certain file into that folder. So far so good.
The problem is that one folder in the path varies slightly from time to time, so a wildcard becomes necessary.
The following code works just fine but obviously misses to create the folder (Reports). So if the folder is not there, it simply does nothing.
for /r "c:\Users\%USERNAME%\AppData\Local\Packages" &&G in ("LocalState\acn\Reports") do #if exist %%G xcopy /s /i /y c:\temp\Reporting "%%G"
The full path is:
c:\Users\FSchneider\AppData\Local\Packages\“WILDCARD"\LocalState\acn\Reports\
Any idea?
Add /d switch in for to indicate you're looking for a directory, not a file
Add * and omit quotes in the wildcard to indicate it's actually a wildcard
No need for if exist now
for /d /r "%LocalAppData%\Packages" %%G in (LocalState\acn.*) do xcopy /s /i /y c:\temp\Reporting "%%G\Reports"
Next script could help.
#ECHO OFF
SETLOCAL enableextensions
set "_fldrtop=%USERPROFILE%\AppData\Local\Packages"
set "_fldrsub=LocalState\acn"
if not "%~1"=="" set "_fldrsub=%~1" :: my testing data, remove this line
set "_fldrlow=Reports"
if not "%~2"=="" set "_fldrlow=%~2" :: my testing data, remove this line
for /F "delims=" %%G in ('dir /B /AD "%_fldrtop%"') do (
if exist "%_fldrtop%\%%G\%_fldrsub%\" (
if exist "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\" (
echo echo "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\"
) else (
echo md "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\"
)
rem echo xcopy /s /i /y c:\temp\Reporting "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\"
)
)
Output:
==>D:\bat\SO\31672436.bat
==>D:\bat\SO\31672436.bat "LocalState\Cache"
md "C:\Users\UName\AppData\Local\Packages\winstore_cw5\LocalState\Cache\Reports\"
==>D:\bat\SO\31672436.bat "LocalState\Cache" 2
echo "C:\Users\UName\AppData\Local\Packages\winstore_cw5\LocalState\Cache\2\"

How to pass parameter from parent for to the child for (for in for) in a batch file?

Trying to pass a parameter incremented by parent for to child for processing, but can't figure why is not working. Tried lots of variations of this code:
for /D %%a in (*) do (
echo Processing %%a
set folder=%cd%\%%a
echo test folder is %folder%
setlocal EnableDelayedExpansion
echo test folder is !folder!
for /R !folder! %%i in (*.log) do (
find /i "error" %%i
)
endlocal
)
Removed the commenting that wasn't in the original code, believed it would help, it didn't. Sorry! Anyway problem is !folder! in 2nd for statement is not being resolved (or resolved as !folder!)
What i need to do is start from a root folder named results where there are lots of other folders that contain other folders witch contain log files. I have to process all primary folders d:\results\test1 test2 .. testn and in every folder i have to generate a report where put files with errors files with size=0 etc + more.
structure looks like
result
test1
phase1
log files
phase2
log files
.
.
phasen
test2
.
.
testn
#echo off
setlocal enabledelayedexpansion
for /D %%a in (*) do (
echo Processing %%a
set folder="%cd%\%%a"
call:testlog !folder!
)
exit/b
:testlog
echo test folder is %1
for /R %1 %%i in (*.log) do find /i "error" "%%i"
You probably should place your setlocal declaration outside the loop:
setlocal EnableDelayedExpansion
for /D %%a in (*) do (
...
Your sample doesn't need delayed expansion
for /D %%a in (*) do (
echo Processing %%a
echo test folder is "%cd%\%%a"
for /R "%cd%\%%a" %%i in (*.log) do (
find /i "error" "%%i"
)
)

Resources