Search code examples
windowsbatch-filecmdwmic

Why is the FOR /f loop in this batch script evaluating a blank line?


I'm trying to write a batch script that obtains (among other things) a list of all of the disk drives the computer has. The basic code looks something like this:

REM Build the list of disk drives to monitor
SETLOCAL enabledelayedexpansion
FOR /f "skip=1 tokens=1 delims=:" %%a in ('"WMIC logicaldisk WHERE drivetype=3 GET deviceid"') do (
    SET "DISK_DATABASES=!DISK_DATABASES!%%a|"
    SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!%%a:\\|"
)

I pretty obviously build two lists with slightly different formats for use later. When I run this, however, the output I get looks something like this:

C|D|E||
C:\\|D:\\|E:\\|:\\|

Now, I expect the trailing pipe in both cases and I can manage that, but I'm really confused why there is an extra blank entry in there. If I run the wmic command manually, I can see that there is indeed a blank line at the end of the output, but my understanding is that /f was specifically supposed to ignore blank lines.

If I turn ECHO on, it looks like that last line is just coming in as a carriage return/newline or similar. Is there a way to do what I'm expecting? Am I missing something? I tried to write an if condition in the loop to exclude this last line, but it was... funky and never worked. I appreciate any/all help.


Solution

  • In this case the last iteration produces not an empty item, and you get your output of C|D|E|| only with echo %DISK_DATABASES%,
    but echo !DISK_DATABASES! will output ||D|E|??

    That's because the last element is a single <CR> character.
    And <CR> characters are directly removed after the percent expansion, but not with delayed expansion.

    You could avoid this, using the percent expansion to remove them

    setlocal EnableDelayedExpansion
    FOR /f "skip=1 tokens=1 delims=:" %%a in ('"WMIC logicaldisk WHERE drivetype=3 GET deviceid"') do (
      set "item=%%a"
      call :removeCR
    
      if not "!item!"=="" (
        SET "DISK_DATABASES=!DISK_DATABASES!!item!|"
        SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!!item!:\\|"
      )
    )
    goto :eof
    :removeCR
    
    :removeCR
    set "Item=%Item%"
    exit /b