0

I've created 2 Windows Batch files so far (1 using forfiles & the other using for) to find all 0 byte files in a directory tree in 4 remote file paths, however they take over 2.5hrs as there are close to 62,000 files & 31 subdirectories.

I'm trying to create get a 3rd version working using a nested for loop with dir but the variable substitution is not working in the inner for loop.

Any ideas why this is the case please & how to fix it?

I also need to include files in the parent directory however it doesn't include them at the moment.

Mostly using Windows Server 2008 R2.

Windows Batch:

@ECHO OFF

@REM Variables
SET my_parent_dir=c:\temp
SET my_dir=""

@REM Loop through sub-dirs (excludes parent dir but need to include it)
FOR /F "usebackq delims=" %%D IN (`"DIR %my_parent_dir% /AD/B/S"`) DO (

    ECHO dir: %%D
    SET my_dir=%%D

    CALL :inner_loop
)
exit /b

:inner_loop
    echo inner dir: = %my_dir%
    
    @REM Loop through files in my_dir directory, sorted by filesize
    FOR /F "delims=" %%F IN ('DIR %my_dir% /A-D/B/OS 2^>nul') DO (

        @REM Variable substitution is NOT working in the inner loop
        ECHO filename+size+datetime: %%F    %%~zF   %%~tF
        
        @REM If filesize > 0 bytes, break out of inner loop
        @REM NOT WORKING as variable substitution not working
        @REM IF %%~zF GTR 0 (
            @REM echo BREAK***
            @REM exit /b
        @REM )

    )
exit /b

Output (note: no filesize nor datetimes):

C:\Temp>list_files_02c.bat
dir: c:\temp\old_1
inner dir: = c:\temp\old_1
filename+size+datetime: old_1_file_3.cmd
filename+size+datetime: old_1_file_1.txt
filename+size+datetime: old_1_file_2.txt
dir: c:\temp\old_2
inner dir: = c:\temp\old_2
filename+size+datetime: old_2_file_2.log
filename+size+datetime: old_2_file_5.txt
filename+size+datetime: old_2_file_3.log
filename+size+datetime: old_2_file_1.cmd
filename+size+datetime: old_2_file_4.txt
dir: c:\temp\old_3
inner dir: = c:\temp\old_3
filename+size+datetime: old_3_file_4.cmd
filename+size+datetime: old_3_file_2.log
filename+size+datetime: old_3_file_3.cmd
filename+size+datetime: old_3_file_1.txt
C:\Temp>

UPDATE - SOLUTION: Have it working now (for remote paths too), thanks all.

Solution Windows Batch:

@ECHO OFF

@REM Save current directory. Required when PushD & PopD are used for remote paths.
SETLOCAL

@REM Variables
@REM SET "my_parent_dir=\\my_pc_name\c$\temp"
SET "my_parent_dir=c:\temp"
SET "my_dir=%my_parent_dir%"

@REM Loop through parent directory files
CALL :inner_loop

@REM Loop through subdirectories (excludes parent directory)
FOR /F "delims=" %%D IN ('DIR "%my_parent_dir%" /B /AD /S') DO (

    ECHO dir %%D
    SET "my_dir=%%D"

    @REM Loop through subdirectory files
    @REM Required so can break out of inner loop but remain in outer loop
    CALL :inner_loop
)
GOTO :end_script


:inner_loop
    ECHO inner dir = %my_dir%
    
    @REM Change to my_dir directory, so variable substitution will work
    PushD "%my_dir%" && (
    
        @REM Loop through files in my_dir directory, sorted by file size, smallest first
        FOR /F "delims=" %%F IN ('DIR /B /A-D /OS 2^>nul') DO (

            @REM If filesize > 0 bytes, break out of inner loop
            IF %%~zF GTR 0 (
                PopD
                EXIT /b
            )

            ECHO filename+size+datetime: %%F    %%~zF   %%~tF

        )
        
    ) & PopD


:end_script
    @REM Return to current directory. Required when PushD & PopD are used for remote paths.
    ENDLOCAL

    ECHO Finished

Solution Output:

C:\Temp>list_files_02c.bat
inner dir = c:\temp
filename+size+datetime: blank_file2.txt 0       07/10/2020 12:12 PM
filename+size+datetime: blank_file1.txt 0       07/10/2020 12:12 PM
dir c:\temp\old_1
inner dir = c:\temp\old_1
filename+size+datetime: old_1_file_3.txt        0       07/10/2020 01:19 PM
dir c:\temp\old_2
inner dir = c:\temp\old_2
filename+size+datetime: old_2_file_2.txt        0       07/10/2020 01:19 PM
filename+size+datetime: old_2_file_5.txt        0       07/10/2020 01:19 PM
dir c:\temp\old_3
inner dir = c:\temp\old_3
filename+size+datetime: old_3_file_4.txt        0       07/10/2020 01:19 PM
Finished

C:\Temp>
Shell D
  • 23
  • 13
  • 1
    The inner loop is not working as expected by you because of __DIR__ outputs the files in directory defined by string assigned to environment variable `my_dir` without file path. So __FOR__ searches in current directory set on starting the batch file for the files output by __DIR__ and cannot find them in the current directory. For that reason __FOR__ cannot determine the file size of a file stored in a different directory than the current directory. I recommend to read also [this answer](https://stackoverflow.com/a/60686543/3074564), especially the __Issue__ chapters. – Mofi Oct 21 '20 at 08:12
  • Ahhh great thanks Mofi – Shell D Oct 21 '20 at 20:42

1 Answers1

3

Just use pushd and popd to and from the directory. As a side note, double quote your variables both sides of the variable and value as like SET "my_parent_dir=c:\temp":

@ECHO OFF

@REM Variables
SET "my_parent_dir=c:\temp"
SET "my_dir="      REM You value should be between = and "

@REM Loop through sub-dirs (excludes parent dir but need to include it)
FOR /F "delims=" %%D IN ('DIR "%my_parent_dir%" /B /AD /S') DO (

    ECHO dir: %%D
    SET my_dir=%%D

    CALL :inner_loop
)
exit /b

:inner_loop
    echo inner dir: = %my_dir%
    pushd "%my_dir%"
    @REM Loop through files in my_dir directory, sorted by filesize
    FOR /F "delims=" %%F IN ('DIR /B /A-D /OS 2^>nul') DO (

        @REM Variable substitution is NOT working in the inner loop
        ECHO filename+size+datetime: %%F    %%~zF   %%~tF
        
        @REM If filesize > 0 bytes, break out of inner loop
        @REM IF %%~zF GTR 0 (
            @REM echo BREAK***
            @REM exit /b
        @REM )

    )
    popd
exit /b

PS!! I removed the backticks and usebackq from the first for loop as it is not required.

Gerhard
  • 22,678
  • 7
  • 27
  • 43
  • I had considered that as I am using pushd & popd in another script with loops that accesses remote paths, so guess I need to do this here, thanks heaps. – Shell D Oct 21 '20 at 20:44
  • Few little tweaks to get it working for remote paths, thanks again Gerhard. Added my working code to my original post as too long to post in this comment. – Shell D Oct 21 '20 at 21:36