I have a batch which scans a directory structure and gives out the size of directorys I defined he should look for.
E.g. the directory '10XXX' contains the subdirectorys '10001', '10002' and '10003'. Now lets say that the batch should look for the dir 'XYZ' in those subdirs. Result is a .csv with informations like '10001\XYZ' 100 Bytes; '10002\XYZ' 2000 Bytes; '10003\XYZ' 0 Bytes.
The problem is the batch scans every directory every time it runs, which takes a lot of time and resources.
My idea is to implement a section into the code that everytime the batch starts scanning a dir it takes a look into a .txt (for example) and when the dir name is found in that file the batch skips the dir.
This is maybe not the most effective solution, but it will take less time and resources than scanning every dir every time.
So different ideas are of course welcome.
Unfortunately I have not enough knowledge to do it myself so I hope that someone could help me.
Code:
#echo off &setlocal
set /p rootfolder=<Enter_Directory_Path_Here.txt
set /p savefolder=<Enter_Save_Directory_Here.txt
set "batpath=%~dp0"
pushd "%rootfolder%"
for /d %%i in (*) do (
set "foldername=%%~nxi"
set "folder=%%i"
>"%batpath%%%~nxi.csv" type nul
for /f "delims=" %%j in ('dir /ad /b "%%i\*"') do (
set "subfolder=%%j"
call :procfolder
)
>"%batpath%%%~nxi.~csv" type nul
for /f "usebackq tokens=1* delims==" %%j in ("%savefolder%\patterns.txt") do (
>>"%batpath%%%~nxi.~csv" findstr /b %%k "%batpath%%%~nxi.csv"
if errorlevel 1 >>"%batpath%%%~nxi.~csv" echo "%%j";"not found"
)
>nul move /y "%batpath%%%~nxi.~csv" "%batpath%%%~nxi.csv"
)
popd
call :cleaner
exit /b
:procfolder
setlocal
for /f "tokens=3" %%i in ('dir /a /-c "%folder%\%subfolder%\"^|findstr /c:"Datei(en)"') do >>"%batpath%%foldername%.csv" echo "%subfolder%";%%i;"Bytes"
for /f "delims=" %%i in ('dir /ad /b "%folder%\%subfolder%\"') do (
set "subfolder=%subfolder%\%%i"
call :procfolder
)
endlocal
exit /b
A sample of reading a text file to match
for /F "tokens=*" %%X in (N:\SomeDirectory\SomeFile.txt) do if /I "%foldername%" EQU "%%X" goto SKIPIT
REM Do your normal stuff here
:SKIPIT
If the exclusion filename is encapsulated in quotes, add the usebackq option:
for /F "usebackq tokens=*" %%X in ("N:\Some Directory\Some File.txt") do if /I "%foldername%" EQU "%%X" goto SKIPIT
REM Do your normal stuff here
:SKIPIT
Related
I could use some help, I've tried similar topics but I couldn't find exactly what I was looking for.
What I need is a batch script which loops through a directory searching for files of type .pro but don't begin with the character {.
The script then searches all the files and echoes the lines which are found between the numbers 574, and 575,.
I've got all the things done except when I try to check for file names I cant get it to work properly and it seems so simple.
My script looks like this:
#echo off
set "sPath=C:\Users\jspajic\Desktop\batskripte\test\test files"
set "ispis=C:\Users\jspajic\Desktop\batskripte\test\Opera_procesi_DataTabovi.txt"
echo %sPath% > %ispis%
pushd %sPath%
for %%f in (*.pro) do ( :: ---> I guess this part needs to be altered
setlocal enabledelayedexpansion
for /f "delims=]" %%a in ('findstr /n /B "574," "%%f"') do (set s=%%a )
if !s! neq 0 (
for /f "delims=]" %%b in ('findstr /n /B "575," "%%f"') do (set kraj=%%b)
if !kraj! neq 0 (
#set /a "ss=s+1"
#set /a "kraj=kraj+0"
#set /a "s=s+0"
if !ss! NEQ !kraj! (
#echo:
echo %%f
#set /a "counter=1"
for /F "tokens=1* delims=:" %%A in ('type "%%f" ^| findstr /n "^"') do (
if !counter! GTR !s! if !counter! LSS !kraj! echo.%%B
#set /a "counter=counter+1"
)
)
)
)
endlocal
) >> %ispis%
popd
I tried with for /f "delims=" %%a in ('dir /B *.pro^|findstr "[A-z]*\.pro" ')
or with similar ideas but I cant get it to work cause I just dont know batch scripts that well.
for %%f in (*.pro) do ( set "dummy=%%f"
setlocal enabledelayedexpansion
if "!dummy:~0,1!" neq "{" (
should solve your problem. Note that it adds an extra level of parentheses, so a matching ) needs to be added after the endlocal but you seem to be adept at doing that.
Assign the filename to a dummy variable, then see whether the 1st character of that dummy is NOT equal to "{" before executing the rest of the code.
From the prompt, set /? will show documentation about substringing - you seem to have delayed expansion worked out.
Because your character does not have a case, (upper | lower), and your search directory is already current; this can be easily catered for using EOL in your For loop:
For /F "EOL={Delims=" %%f In ('Dir/B/A-D *.pro') Do (
use for /f with dir, filtered by findstr (eliminate every token that starts with {):
for /f "delims=" %%f in ('dir /b /a-d *.pro^|findstr /vb "{"') do (
i'm updating a big save script and i need to compare 2 folders recursively. I think i'm pretty close but can't understand what's missing...
The code is the following :
set Rep1=f:\album1
set Rep2=f:\album2
set logfile=f:\logfile.txt
for /r "%Rep1%\" %%i in (*) do (
fc "%%i" "%Rep2%\%%~nxi"
iF ERRORLEVEL == 1 echo "%%i" et "%Rep2%\%%~nxi" Sont differents >> %logfile%
iF ERRORLEVEL == 2 echo "%%i" et "%Rep2%\%%~nxi" Un des fichier est manquant >> %logfile%
)
pause
The problem is that it compares all files like f:\album1\folder1\file1.txt with f:\album2\file1.txt so the comparing is always wrong... You can see the result in the picture:
If any of you find a solution, thank you a lot !
Vincs
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "targetdir=U:\destdir"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*" '
) DO (
SET "foundfile="
FOR /f "delims=" %%c IN (
'dir /s /b /a-d "%targetdir%\%%~nxa" 2^>nul'
) DO (
SET foundfile=Y
FC /b "%%a" "%%c" >NUL
IF ERRORLEVEL 1 ECHO different "%%a" "%%c"
)
IF NOT DEFINED foundfile ECHO missing "%%a" from "%targetdir%"
)
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%targetdir%\*" '
) DO (
SET "foundfile="
FOR /f "delims=" %%c IN (
'dir /s /b /a-d "%sourcedir%\%%~nxa" 2^>nul'
) DO (
SET foundfile=Y
)
IF NOT DEFINED foundfile ECHO missing "%%a" from "%sourcedir%"
)
GOTO :EOF
You would need to change the settings of sourcedir and targetdir to suit your circumstances.
One problem with your approach is that the file %%i is compared to "%Rep2%\%%~nxi" which means only in %rep2%, not in the subdirectory.
Another problem is
IF ERRORLEVEL == 1 echo "%%i" et "%Rep2%\%%~nxi" Sont differents >> %logfile%
which compares the literal string ERRORLEVEL to the literal string 1 so will not find a match. To use your method, you would have to turn delayedexpansion on with a setlocal enabledelayedexpansion statement and then use IF !ERRORLEVEL!==1 ...
The solution posted above compares files that have the same name and extension wherever they are found on the tree, so if file1.txt is anywhere in the first tree, then it will be compared to all the file1.txt files found anywhere in the second tree.
Note also that there is a standard anomaly when dealing with a standard system that gives files both a long and a short name. Each file potentially has two names - and dir matches on either name.
Magoo's answer already points out the major problems of your code.
However, the solution he provided uses only the file names for finding the files to compare, so it will fail if files with equal names occur at different locations in the source and target directories, or if multiple files with equal names occur within any of the directory trees.
Here is a similar solution, based on the dir /S command, which also requires each file name in the trees to be unique and to occur at the same location within source and target (it does not check for files present in only one of the source or target trees):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Provide source and target directory paths here:
set "SOURCE=.\source"
set "TARGET=.\target"
rem Convert relative paths to absolute ones:
for %%D in ("%SOURCE%") do set "SOURCE=%%~fD"
for %%D in ("%TARGET%") do set "TARGET=%%~fD"
for /F "eol=| delims=" %%I in ('
2^> nul dir /B /S /A:-D "%SOURCE%\*.*"
') do (
set "SRC=%%~fI"
for /F "eol=| delims=" %%J in ('
2^> nul dir /B /S /A:-D "%TARGET%\%%~nxI"
') do (
set "TRG=%%~fJ"
setlocal EnableDelayedExpansion
> nul fc /B "!SRC!" "!TRG!" || echo "!SRC!" and "!TRG!" differ.
endlocal
)
)
endlocal
exit /B
This code snippet compares only files which occur in both source and target directory trees. If respective files are different, a related message is returned.
To overcome the issue with equal file names at different locations, let us use the xcopy /L command, because this is capable of returning a list of paths relative to the source directory (the /L option prevents xcopy from copying any files; the appended find command filters out the ? File(s) summary lines):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Provide source and target directory paths here:
set "SOURCE=.\source"
set "TARGET=.\target"
rem Convert relative paths to absolute ones:
for %%D in ("%SOURCE%") do set "SOURCE=%%~fD"
for %%D in ("%TARGET%") do set "TARGET=%%~fD"
pushd "%SOURCE%"
for /F "eol=| delims=" %%I in ('
2^> nul xcopy /L /S /Y ".\*.*" "%TEMP%\" ^| find ".\"
') do (
set "SRC=%%~fI"
pushd "%TARGET%"
for /F "eol=| delims=" %%J in ('
2^> nul xcopy /L /Y "%%~I" "%TEMP%\" ^| find ".\"
') do (
set "TRG=%%~fJ"
setlocal EnableDelayedExpansion
> nul fc /B "!SRC!" "!TRG!" || echo "!SRC!" and "!TRG!" differ.
endlocal
)
popd
)
popd
endlocal
exit /B
This code snippet also compares only files which occur in both source and target directory trees. If you also want to check whether each fils is present in both source and target trees, check out Magoo's answer which provides a good idea of how to accomplish that (two-loop approach).
I have a folder full of text files that I need to split based on the (optional) presence of a delimiter. I found an answer for how to actually split the file here: Split text file into 2 files by separator
#echo off&setlocal
set "file=_frmCore.frm"
for /f "delims=[]" %%i in ('^<"%file%" find /n "SearchTermHere"') do set "split=%%i"
(for /f "tokens=1*delims=[]" %%i in ('^<"%file%" find /n /v ""') do if %%i lss %split% echo(%%j)>"%file%.new1"
<"%file%">"%file%.new2" more +%split%
type "%file%.new?"
Works great for what it is, but I need a few refinements and not sure where to start. Looking for:
Wrap it in a loop for all files in the directory (no subfolders to worry about)
"SearchTermHere" is the first on a line (the only on a line), with a specific term on the previous line that I'd rather match for safety... how can I tell it "PreviousLine/r/nSearchTermHere/r/n"? Unsure of the correct syntax here.
Rather than creating two new files, move the "after search term" portion to a new file and remove it from the original
Parameterize folder name to operate in so I can call from other programs
(apologies... I've tried deciphering this code and finding out what does what and trying to go from there, but this stuff is not my cup of tea and a strong push in the right direction would be wonderful)
#ECHO OFF >NUL
SETLOCAL enableextensions
rem enabledelayedexpansion
set "_files=*.frm"
set "_sfind=SearchTermHere"
if not "%~1"=="" if exist "%~1\" (
pushd "%~1"
set "_popd=popd"
) else ( set "_popd=" )
for /F "delims=" %%G in ('findstr /m "^%_sfind%$" %_files%') do (
type NUL > "%%G.new1"
type NUL > "%%G.new2"
for /f "delims=:" %%i in ('findstr /n "^%_sfind%$" "%%G"') do (
for /f "tokens=1* delims=:" %%I in ('findstr /n "^" "%%G"') do (
if %%I lss %%i (
>> "%%G.new1" echo(%%J
)
if %%I gtr %%i (
>> "%%G.new2" echo(%%J
)
)
)
rem remove `ECHO` from next line no sooner than debugged!
ECHO move /Y "%%G.new1" "%%G"
type "%%G.new?"
)
%_popd%
Changes made in your code:
Wrap it in a loop for all files in the directory: see for /F "delims=" %%G loop against all files matching your criteria: findstr /m "^%_sfind%$" %_files%.
"SearchTermHere" is the first on a line (the only on a line): ^=beginning of line and $=end of line in findstr /m "^%_sfind%$" %_files%; used findstr command rather than find.
Rather than creating two new files, move the "after search term" portion to a new file and remove it from the original: see the move /Y "%%G.new1" "%%G" workaround. Operational move command is ECHOed here merely for debugging purposes. Remove ECHO from that line no sooner than debugged!
Parameterize folder name to operate in so I can call from other programs:
call "batch path\31749577.bat" "folder path"
see %~1 test: if a parameter is supplied to the batch and represents a folder, (more in Command Line arguments (Parameters)) and
see pushd - popd pair: PUSHD changes the current directory/folder and store the previous folder/path for use by the POPD command.
The tricky <"%%G">"%%G.new2" more +%%i command substituted with less effective but clear to understand if %%I gtr %%i ( ... inside the %%I loop. However, next code snippet (entire %%G loop) will work as well:
for /F "delims=" %%G in ('findstr /m "^%_sfind%$" %_files%') do (
for /f "delims=:" %%i in ('findstr /n "^%_sfind%$" "%%G"') do (
>"%%G.new1" (for /f "tokens=1* delims=:" %%I in ('
findstr /n "^" "%%G"') do if %%I lss %%i echo(%%J)
<"%%G">"%%G.new2" more +%%i
)
rem remove `ECHO` from next line no sooner than debugged!
ECHO move /Y "%%G.new1" "%%G"
type "%%G.new?"
)
Excuse me. Although your description is extensive, it is also confusing. The Batch file below:
Search for a line that is "SearchTermHere".
If the previous line is "PreviousLine":
Move from line after SearchTerm up to end of file to another file
Repeat previous process on all files in folder.
.
#echo off
setlocal EnableDelayedExpansion
set "find=SearchTermHere"
set "prevLine=PreviousLine"
rem Process the folder given in parameter
cd %1
rem Process all files in folder
for /F "delims=" %%F in ('dir /A-D /B') do (
rem Get the line number of the search line - 1
set "numLines="
for /F "delims=:" %%a in ('findstr /N "^%find%$" "%%F"') do set /A "numLines=%%a-1"
if defined numLines (
rem Open a code block to read-input-file/create-output-file
< "%%F" (
rem Copy numLines-1 lines
for /L %%i in (1,1,%numLines%) do (
set "line="
set /P "line="
echo(!line!
)
rem If the line before search is prevLine
if "!line!" equ "%prevLine%" (
rem Copy just the search line to original file
set /P "line="
echo !line!
rem and copy the rest of lines to another file
findstr "^" > "%%~nF-PART2%%~xF"
)
) > "%%F.tmp"
if exist "%%~nF-PART2%%~xF" (
rem Replace original file with created output file (first part)
move /Y "%%F.tmp" "%%F" > NUL
) else (
rem Remove the output file
del "%%F.tmp"
)
)
)
For a further explanation of this method, see this post.
Sorry, I was unable to use either of the proposed solutions. However they did help - I spent the last two days learning about the (odd) syntaxes and operations involved in batch files and came up with the following. It doesn't do quite everything that I was looking for (and I altered the program that outputs the files a bit for further support), but it does get the job done:
#ECHO off
setlocal EnableDelayedExpansion
:: change the working directory to match the input
cd /D %~d1
cd %~p1\
:: loop all .frm files and find the CodeBehindForm string
for %%F in (*.frm) do (
for /F "delims=[]" %%a in ('^<%%F find /n "CodeBehindForm"') do (
if %%a gtr 0 (
for /F "tokens=1*delims=[]" %%i in ('^<"%%F" find /n /v ""') do if %%i gtr %%a echo(%%j)>>"%%~nF.vb"
for /F "tokens=1*delims=[]" %%i in ('^<"%%F" find /n /v ""') do if %%i lss %%a echo(%%j)>>"%%~nF.fwm"
:: if the codebehind was found and parsed out, there's a .fwm and .vb file
:: remove the original
if exist %%~nF.vb del %%F
)
)
:: change the .fwm extensions back to their original .frm extensions
ren *.fwm *.frm
I'm sure it's not "correct" in many ways, but for now it gets the job done.
Thanks for the help.
This is a very specific question, so I've separated it into 3 parts.
Look in all subfolders for a certain file: world.sav, but only 1 level down, i.e.
C:\workingdir\foo\world.sav
C:\workingdir\bar\world.sav
C:\workingdir\baz\world.sav
C:\workingdir\qux\world.sav
is fine, but
C:\workingdir\foo\bar\world.sav
C:\workingdir\world.sav
isn't, etc.
Sort these world.sav files by date modified (newest first).
Display the name of the subfolder each world.sav file is in, in the previously sorted order. i.e. if the above list was date-sorted into
C:\workingdir\qux\world.sav (newest)
C:\workingdir\bar\world.sav
C:\workingdir\foo\world.sav
C:\workingdir\baz\world.sav (oldest)
then the output would be
qux
bar
foo
baz
I've tried numerous methods involving DIR, FORFILES and manipulation of variables, but the 2 main problems I've come across so far are
Both commands mentioned above will arrange by subfolder, then by date, and I can't find a way to avoid it.
Date formatting. It appears to be different for every localization of Windows, and I really want this to be locale-independent.
Also, it must support spaces in folder names.
EDITED version with a wait message:
#echo off
echo Please wait...
cd /d "c:\workingdir"
(for /d %%a in (*) do #robocopy "%%a" "%%a" world.sav /L /nocopy /is /njh /njs /ndl /nc /ns /ts)|(
#cls
for /f "tokens=2*" %%b in ('sort /r') do #for %%z in ("%%~dpc\.") do #echo %%~nz
)
cd /d "%~dp0"
echo.
pause
original version below
This works here:
robocopy is used on each folder in the directory to generate a list (UTCdate time drv:\path\world.sav format) and that is sorted to get most recent at the top of the list, which the second for parses to extract the drv:\path\folder\world.sav and the last for loop prints out just the folder name.
#echo off
cd /d "c:\workingdir"
(for /d %%a in (*) do #robocopy "%%a" "%%a" world.sav /L /nocopy /is /njh /njs /ndl /nc /ns /ts)|for /f "tokens=2*" %%b in ('sort /r') do #for %%z in ("%%~dpc\.") do #echo %%~nz
pause
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a count=0
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" '
) DO IF exist "%sourcedir%\%%a\world.sav" CALL :set$ "%%a"
IF %count%==0 ECHO No files found&GOTO :EOF
IF %count%==1 ECHO %$1%&GOTO :EOF
:sortol
SET /a start=1
SET /a swap=0
:sortil
CALL :compdt
IF %start% neq %count% GOTO sortil
IF %swap% neq 0 GOTO sortol
FOR /l %%a IN (1,1,%count%) DO CALL ECHO %%$%%a%%
GOTO :EOF
:set$
SET /a count+=1
SET "$%count%=%~1"
GOTO :eof
:compdt
CALL SET f1=%%$%start%%%
SET /a START +=1
CALL SET f2=%%$%start%%%
FOR /f %%a IN (
'echo f^|xcopy /L /y /d "%sourcedir%\%f1%\world.sav" "%sourcedir%\%f2%\world.sav"'
) DO SET copies=%%a
IF %copies%==0 GOTO :EOF
SET /a swap +=1
SET /a START -=1
SET "$%start%=%f2%"
SET /a START +=1
SET "$%start%=%f1%"
GOTO :eof
This worked for me. You'd need to set sourcedir to suit your purpose.
Essentially, it builds a list of the next-level-down directory names which contain the target filename in variables $1...$whatever, then sorts the names using a simple bubble-sort which relies on the characteristics of xcopy. XCOPY's /L switch simply lists the files that would be copied; /y tells it to 'go ahead (and not copy)' and /d says 'only later files.ECHOingftellsxcopythat the desired "copy" is a file-copy, so it responds1 file(s) copiedor0...` as its last line, depending on whether the source file was later than the destination.
To reverse the order, simply change the if %copies%==0 to if %copies%==1
An idea :
#echo off
Setlocal EnableDelayedExpansion
set $WorkDir="C:\eh\guh\blugh\fneh\mork\workingdir"
for /f "tokens=*" %%a in ('dir /s/b/a-d %$WorkDir%') do (
for /f "tokens=9 delims=\" %%b in ('echo %%a') do (
if /i "%%b"=="world.sav" call:next "%%~pa" %%~ta
)
)
::Resultat
for /f "tokens=2 delims==" %%r in ('set #') do echo %%r
exit/b
:next
for /f "tokens=7 delims=\" %%c in ('echo %~1') do set $Path=%%c
for /f "tokens=1-3 delims=/" %%c in ('echo %~2') do set #%%e%%d%%c=!$path!
I work with hundreds of thousands of folders/files, most of which have certain log files. It takes a lot of time to manually navigate through the folders to grab the logs, so Ive been using a script to do it.
Its a 2 parter. First part runs overnight to parse all of the directories (they change daily and new logs are added very often, so I index everything nightly to keep the index current).
This first part is automatic and I never touch it, it just runs nightly. Output goes to a txt file, which is used when I execute the second script.
Second script is where I put in keywords of what log I am looking for. This script relies on the txt output from the first script to quickly locate the file and pull it down.
(The reason I do it this way is because its a 5 second task to parse 300,000 line text file looking for a file, and its a 15-30 minute job to search (index all of the network shares). This way I can get my logs in 5 seconds and not 30+ minutes).
Prior to last week the log directories consisted of about 5000 files and folders. This past weekend IT switched over to a new system, and it is now consisting of over 500,000 files and folders. They dumped archives, and a bunch of other files in there that I do not need.
First script used to index it in about 10-15 minutes (its a network share, actually 4 network shares), no problem overnight. While now this is a 4+ hour feat. I need to be able to exclude certain directories during indexing thereby reducing the 500,000 file/folder count back down to under 5,000.
Ive been using this command to index:
dir /b /-d /-p /s /A:-D > C:\output.txt
I need have the indexing skip any directory containing the words "Common" or "Old" in them, and potentially others as well. The goal is to save time by not going inside of these directories at all.
I tried looking into PowerShell to do this, but I know nothing about it.
I need the output to be in the following format:
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\dbInstaller.exe
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\DisplayDriver.nvi
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\DisplayDriverExt.dll
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\license.txt
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\mcu.ex_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvae.inf
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvak.inf
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvapi.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvapi64.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvcompiler.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvcompiler32.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvcplsetupeng.exe
Thanks!
#ECHO OFF
SETLOCAL
SET "sourcedir=."
(
FOR /f "delims=" %%a IN (
'dir /b /s /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO ( FOR /f "delims=" %%b IN ('dir /b /a-d "%%a" 2^>nul') DO ECHO(%%a\%%b
)
)>newfile.txt
GOTO :EOF
I used a file named q22903564.txt containing exclusion words for my testing.
Produces newfile.txt.
Naturally, choice of sourcedir, q22903564.txt and newfile.txt are all in your court...
#ECHO OFF
SETLOCAL
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
SET "sourcedir=."
:: get a dir listing from the root
(
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO (ECHO("%%~fa")
)>"%tempfile%b"
:again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /ad "%%~a\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO FOR /f "delims=" %%c IN ('ECHO("%%~a\%%b"^|findstr /x /v /i /l /g:"%tempfile%b"') DO ECHO "%%~c"
)
)>"%tempfile%c"
FOR %%a IN ("%tempfile%c") DO SET /a sizec=%%~za
IF %sizec% gtr 0 TYPE "%tempfile%c">>"%tempfile%b"&GOTO again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /a-d "%%~a\*" 2^>nul'
) DO ECHO(%%~a\%%b
)
)>newfile.txt
DEL "%tempfile%*"
GOTO :eof
Well - need to charge you extra for doing what, according to some, is impossible.
#ECHO OFF
SETLOCAL
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
SET "sourcedir=."
:: get a dir listing from the root
(
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO (ECHO("%%~fa")
)>"%tempfile%b"
SET /a sizec=0
:again
SET "skipcnt=usebackq"
IF %sizec% gtr 0 (
FOR /f %%a IN ('type "%tempfile%b" ^|find /c /v ""') DO SET "skipcnt=usebackqskip=%%a"
TYPE "%tempfile%c">>"%tempfile%b"
)
(
FOR /f "%skipcnt%delims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /ad "%%~a\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO FOR /f "delims=" %%c IN ('ECHO("%%~a\%%b"^|findstr /x /v /i /l /g:"%tempfile%b"') DO ECHO "%%~c"
)
)>"%tempfile%c"
FOR %%a IN ("%tempfile%c") DO SET /a sizec=%%~za
IF %sizec% gtr 0 GOTO again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /a-d "%%~a\*" 2^>nul'
) DO ECHO(%%~a\%%b
)
)>newfile.txt
DEL "%tempfile%*"
GOTO :eof
Third time's a charm. This version works out how many lines of directory it's already processed and skips those lines when re-processing the concatenated lists b and c. IOW, it only processes the additions.
And in typing this, I've realised there's another little simplification... have to wait for morning tea, though...
#ECHO OFF
SETLOCAL
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
SET "sourcedir=."
:: get a dir listing from the root
(
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO ECHO(%%~fa
)>"%tempfile%c"
SET /a sizec=0
:again
SET "skipcnt=usebackq"
IF %sizec% neq 0 FOR /f %%a IN ('type "%tempfile%b" ^|find /c /v ""') DO SET "skipcnt=usebackqskip=%%a"
TYPE "%tempfile%c">>"%tempfile%b"
(
FOR /f "%skipcnt%delims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /ad "%%a\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO ECHO(%%a\%%b
)
)>"%tempfile%c"
FOR %%a IN ("%tempfile%c") DO SET /a sizec=%%~za
IF %sizec% gtr 0 GOTO again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /a-d "%%a\*" 2^>nul'
) DO ECHO(%%a\%%b
)
)>newfile.txt
DEL "%tempfile%*"
GOTO :EOF
This time for sure! (no lion's roar thought)
I realised that the re-filtering against the original tempfileb content was redundant - and removing that meant that the quoting regime to overcome awkward characters could be scaled back. Then in reality the original file was the original addition (tempfilec) to an empty tempfileb, so - a little reorganisation and hand-waving (because 'skip=0' is invalid) and the result is that the only directories that are scanned later are thos that have beed added in the last iteration, optimising the directory-scan methodology.
Now the consequences are that the resultant list will be \a\, \b\, \c\, \a\a1\, \b\b1\, and so on - but a simple sort of the result should take care of that, if required.
This may help: it excludes the terms in line 3 where you see "Common Old"
It creates a list of the folders, filters out the excluded terms, and uses the remaining folders to create the list.
If you only want *.log *.txt files etc then it could be made more efficient again - otherwise remove the *.log *.txt terms in the batch file in line 7
#echo off
dir /b /ad /s /-p > "C:\output.txt"
findstr /v /i "Common Old" "C:\output.txt" >"C:\output2.txt"
del "C:\output.txt"
for /f "usebackq delims=" %%a in ("C:\output2.txt") do (
pushd "%%a"
for /f "delims=" %%b in ('dir *.log *.txt /b /-p /a-d') do >>"C:\output.txt" echo(%%a\%%b
popd
)