Why does the FOR / f loop in this batch script evaluate an empty string?

I am trying to write a script package that receives (among other things) a list of all the disk drives of a computer. The main 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 am pretty explicitly creating two lists with slightly different formats for use later. However, when I run this, the output I get looks something like this:

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

Now I expect a trailing tube in both cases, and I can handle it, but I'm really confused why there is an extra blank entry there. If I run the wmic command manually, I see that there really is an empty line at the end of the output, but I understand that /f was specifically designed to ignore empty lines.

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

+8
batch-file
Nov 04 2018-11-11T00:
source share
7 answers

In this case, the last iteration produces a non-empty element, and you get your result C|D|E|| only with echo %DISK_DATABASES% ,
but echo !DISK_DATABASES! will output ||D|E| ??

This is because the last element is the only <CR> character.
And the <CR> characters are immediately deleted after percentage expansion, but not with extension delay.

You could avoid this by using a percentage extension 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 
+5
Nov 05 2018-11-11T00: 00Z
source share

I just got down to this topic. I used 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 ( 
+11
Jun 18 '14 at 15:06
source share

According to http://ss64.com/nt/for_f.html

Many of the new commands and utilities (for example, WMIC) output text files in Unicode format, they cannot be read by the FOR command, which expects ASCII. To convert the file format, use the TYPE command.

So it looks like WMIC and FOR are not playing well together.

+4
Nov 04 2018-11-11T00:
source share

I have discovered a more efficient and reliable method for removing unwanted <CR> from the end of each line. There is no temporary file, and no CALL is required.

I do not understand the mechanism of how FOR / F converts WMIC unicode output to ASCII. Normally FOR / F cannot read unicode. But, nevertheless, it works, each converted string ends with <CR><CR><LF> . FOR / F splits the lines on each <LF> , and then, if the last character in the string <CR> , it deletes the last <CR> , in this case leaving an undesirable <CR> .

The solution is to simply pass each line through another FOR / F :-)

 @echo off setlocal enableDelayedExpansion for /f "skip=1 delims=" %%A in ( 'wmic logicaldisk where "drivetype=3" get deviceid' ) do for /f "tokens=1 delims=:" %%B in ("%%A") do ( set "disk_databases=!disk_databases!%%B|" set "drives_to_monitor=!drives_to_monitor!%%B:\\|" ) 

This method is more reliable and then uses the normal extension, because you do not need to worry about quoting or escaping special characters. For example, a CALL method that uses a normal extension cannot process a string like "this & that" & the other . But this method has no problems with such a string.

+3
Feb 02 '13 at 4:59
source share

My standard idiom for working with this is to write the output from WMIC to a temporary file, then use TYPE (which reduces UTF16 to ASCII) to pass this to FOR, for example:

 :: Standard environment setup setlocal enabledelayedexpansion :: Every variable whose name starts with "tf" will identify a temporary :: file - remove any such variables inherited from the parent environment for /f %%V in ('set tf') do set %%V= :: Create some temporary filenames. Prefix all of them with this script's :: own name to avoid clashes with those owned by other scripts. for /l %%I in (1,1,4) set tf%%I="%temp%\%~n0-temp%%I.txt" :: Use temp file to work around coding mismatch between WMIC out and FOR in wmic product where "name like 'Microsoft Office %% 2010'" get packagecache >!tf1! for /f "skip=1" %%P in ('type !tf1!') do if exist "%%~P" msiexec /x "%%~P" /passive /norestart :: Before quitting script, clean up temporary files for /f %%V in ('set tf') do if exist "%%~V" del /f /q "%%~V" endlocal 
0
May 19 '13 at 8:55
source share

Run the following command:

 wmic blah /value | find "=" >> wherever 

The output will be:

 field=value 

Please note that there will be no extra lines.

0
Jun 12 '13 at 14:37
source share

Add ^| findstr . ^| findstr . and you will only get non empty lines

     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" ^ |  findstr. ') do (
         SET "DISK_DATABASES =! DISK_DATABASES! %% a |"
         SET "DRIVES_TO_MONITOR =! DRIVES_TO_MONITOR! %% a: \ |"
     )
    
0
Jan 11 '17 at 17:37 on
source share



All Articles