Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 956
Morinar Avatar asked Nov 04 '11 20:11

Morinar


People also ask

How does for loop work in batch?

Batch file for loop – looping through a range of values /L signifies that for loop is used for iterating through a range of values. Lower limit is the value from which loop will start until it reaches the Upper limit and the increment is the value with which lower limit will be increased during each iteration.

What does %% mean in batch script?

Use double percent signs ( %% ) to carry out the for command within a batch file. Variables are case sensitive, and they must be represented with an alphabetical value such as %a, %b, or %c. ( <set> ) Required. Specifies one or more files, directories, or text strings, or a range of values on which to run the command.

What does %% f do?

%f is a "for-variable" or "loop-variable" (I also heard the term "Metavariable"). It's valid only within the for loop and has no meaning after the for loop ends. Environment variables are manipulated with the set command (see set /? ), for for-variables, there are "modifiers" (see for /? )

What is F in batch file?

%%parameter A replaceable parameter: in a batch file use %%G (on the command line %G) FOR /F processing of a text file consists of reading the file, one line of text at a time and then breaking the line up into individual items of data called 'tokens'.


2 Answers

I just came over this topic. I've been using findstr /v to exclude empty lines:

FOR /f "usebackq skip=1 tokens=1 delims=:" %%a in (`WMIC logicaldisk WHERE "drivetype=3" GET deviceid ^| findstr /v /r "^$"`) do (
like image 93
dmitry Avatar answered Oct 01 '22 10:10

dmitry


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
like image 44
jeb Avatar answered Oct 01 '22 09:10

jeb