Search code examples
batch-filewindows-11

How to right align the output of the file size in a custom directory listing?


I am trying to make a custom directory listing in batch using for loops.

This is the code:

for /F "tokens=* UseBackQ" %%g IN (`dir /b %2`) do (   
    echo  ^| %%~ag %%~tg %%~zg %%~nxg && echo  ^|
)

The output with %2 being E:\ is:

 | d---------- 2022-08-19 02:14 PM 0 AppTemp
 |
 | --a-------- 2022-08-06 11:40 PM 971 learned.py
 |
 | --a-------- 2022-08-19 05:00 PM 4269 main.cmd
 |

I would like the file size to be like this:

 | d---------- 2022-08-19 02:14 PM    0 AppTemp
 |
 | --a-------- 2022-08-06 11:40 PM  971 learned.py
 |
 | --a-------- 2022-08-19 05:00 PM 4269 main.cmd
 |

How can I make it like this?


Solution

  • There could be used the following a little bit commented batch file code:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    
    rem Make the directory passed as second argument the current directory
    rem checking if a second, non-empty argument string is passed at all to
    rem the batch file and with checking if that is really a directory name.
    
    set "RestoreCurrentDirectory="
    if "%~2" == "" (
        echo No directory specified as second argument, listing the directory:
        echo "%CD%"
        echo(
    ) else pushd "%~2" && set "RestoreCurrentDirectory=1" || (
        echo "%~2" is not a valid directory.
        echo(
        exit /B 1
    )
    
    rem Get the file size of the largest file in the current directory
    rem assigned to environment variable with the name LeadingSpaces.
    
    set "LeadingSpaces="
    for /F "eol=| delims=" %%I in ('dir /A-D /B /O-S 2^>nul') do (
        set "LeadingSpaces=%%~zI"
        if defined LeadingSpaces goto GetSpaces
    )
    set "LeadingSpaces= "
    set "NumberSpaces=1"
    goto OutputFileNames
    
    rem Replace all digits in file size of largest file by spaces. The string
    rem value of the environment variable LeadingSpaces has exactly the same
    rem number of spaces as the file size of the largest file in the current
    rem directory has as string. Next determine the number of spaces using code
    rem from https://www.dostips.com/DtTipsStringOperations.php#Function.strLen
    
    :GetSpaces
    setlocal EnableDelayedExpansion
    for %%I in (0 1 2 3 4 5 6 7 8 9) do set "LeadingSpaces=!LeadingSpaces:%%I= !"
    set "TempString=#%LeadingSpaces%"
    set "NumberSpaces=0"
    for /L %%I in (12,-1,0) do (
        set /A "NumberSpaces|=1<<%%I"
        for %%J in (!NumberSpaces!) do if "!TempString:~%%J,1!" == "" set /A "NumberSpaces&=~1<<%%I"
    )
    endlocal & set "LeadingSpaces=%LeadingSpaces%" & set "NumberSpaces=%NumberSpaces%"
    
    rem List all files in the specified directory with right aligned file size
    rem with the definition of environment variable FileSize with the leading
    rem spaces on which the real file size is appended and output only the last
    rem NumberSpaces characters of the file size string with spaces at beginning.
    
    :OutputFileNames
    for /F "eol=| delims=" %%I in ('dir /A-D /B 2^>nul') do (
        set "Attributes= | %%~aI"
        set "FileTime=%%~tI"
        set "FileSize=%LeadingSpaces%%%~zI"
        set "FileName=%%~nxI"
        setlocal EnableDelayedExpansion
        echo !Attributes! !FileTime! !FileSize:~-%NumberSpaces%! !FileName!& echo  ^|
        endlocal
    )
    
    if defined RestoreCurrentDirectory popd
    endlocal
    

    ATTENTION:

    The Windows Command Processor cmd.exe fails to get the file attributes with %%~aI, the last modification time with %%~tI and the file size with %%~zI of a file with sharing access denied completely in comparison to command DIR of cmd.exe which gets the data directly from the file system.

    If this batch file is called with second argument being %SystemDrive%\ and the root directory of the system drive contains only the two files hiberfil.sys and pagefile.sys, the output of the batch file is:

     |     hiberfil.sys
     |
     |     pagefile.sys
     |
    

    The file attributes hidden and system of hiberfil.sys and pagefile.sys do not matter. The sharing violation is the cause of not getting all the data of these two files for the output.

    It would be perhaps better to run DIR and parse its output, but the date/time format of the output of DIR depends on region/country configured for the current user account which makes it most likely not possible to code the batch file for working on all Windows computers.

    To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.

    • dir /?
    • echo /?
    • endlocal /?
    • exit /?
    • for /?
    • if /?
    • popd /?
    • pushd /?
    • rem /?
    • set /?
    • setlocal /?

    Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.

    See also single line with multiple commands using Windows batch file for an explanation of the unconditional command operator & and the conditional command operators && and ||.