1

Here is my batch script which gives you the list of hard drive letters:

@echo off
setlocal enabledelayedexpansion
for /f "skip=1 tokens=1,2 delims=: " %%a in ('WMIC LogicalDisk Where "DriveType='3'" Get DeviceID') do (
   set "_DRIVE.LETTERS.USED=!_DRIVE.LETTERS.USED!%%a:\ ; "
)
echo %_DRIVE.LETTERS.USED%

My expected output is: C:\ ; D:\ But it will print C:\ ; D:\ ; :\ ;

How to remove last extra :\ ;?

aschipfl
  • 33,626
  • 12
  • 54
  • 99
Inside Man
  • 4,194
  • 12
  • 59
  • 119
  • Filter for the relevant lines: `... Get DeviceID^|find ":"') do ...` to get rid of empty entries and `echo %_DRIVE.LETTERS.USED:~0,-3%` to delete the last space/semicolon/space. – Stephan Dec 03 '19 at 19:51
  • @Stephan Thank you works great. please submit it as the answer. and could you please tell me how to solve this one in short? `https://stackoverflow.com/questions/59164308/counter-will-not-add-inside-a-loop-batch-script?noredirect=1#comment104552640_59164308` – Inside Man Dec 03 '19 at 19:55
  • I commented on your other question. Interesting, you *did* use delayed expansion here, but *forgot* it there. (don't mind - that will happen again and again...) – Stephan Dec 03 '19 at 20:14

2 Answers2

3

Filter for the relevant lines: ... Get DeviceID^|find ":"') do ... to get rid of empty entries and echo %_DRIVE.LETTERS.USED:~0,-3% to delete the last space/semicolon/space:

@echo off
setlocal enabledelayedexpansion
for /f "skip=1 tokens=1,2 delims=: " %%a in ('WMIC LogicalDisk Where "DriveType='3'" Get DeviceID ^|find ":"') do (
   set "_DRIVE.LETTERS.USED=!_DRIVE.LETTERS.USED!%%a:\ ; "
)
echo %_DRIVE.LETTERS.USED:~0,3%
Stephan
  • 53,940
  • 10
  • 58
  • 91
3

The empty line is in fact an artefact (an orphaned carriage-return character) that appears when using for /F to convert the Unicode output of wmic to ASCII/ANSI text. To get rid of such things just wrap around another for /F loop*:

@echo off
setlocal EnableDelayedExpansion
for /F "skip=1" %%I in ('wmic LogicalDisk where "DriveType=3" get DeviceID') do (
    for /F %%J in ("%%I") do (
        set "_DRIVE.LETTERS.USED=!_DRIVE.LETTERS.USED!%%J\ ; "
    )
)
endlocal & echo %_DRIVE.LETTERS.USED%

I also removed the options tokens (default: 1) and delims (default: SPACE, TAB) since they are not really needed here any more (splitting off the colon and then re-appending it in the loop body makes no sense).


A more general solution, which even works when there are SPACEs within the values, is to use the /VALUE option of wmic, because then the returned values are no longer padded with trailing SPACEs, which is the case without /VALUE. To split off the preceding value name in the changed output (like DeviceID=C:), set the appropriate tokens and delims options of the inner for /F loop:

@echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%I in ('wmic LogicalDisk where "DriveType=3" get DeviceID /VALUE') do (
    for /F "tokens=1* delims==" %%J in ("%%I") do (
        set "_DRIVE.LETTERS.USED=!_DRIVE.LETTERS.USED!%%K\ ; "
    )
)
endlocal & echo %_DRIVE.LETTERS.USED%

This would remove any leading equal-to signs from the values, but this is not going to happen with the values at hand anyway, and this should generally happen extremely rarely.


*) This two-loop method is credited to user dbenham &dash; see his answer to Why is the FOR /f loop in this batch script evaluating a blank line? as well as this external article WMIC and FOR /F : A fix for the trailing <CR> problem.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Just noting: `"splitting off the colon and then re-appending it in the loop body makes no sense"` - That's true only with this nested `for` approach. With a simple `for`, not removing the colon results in that ugly remaining `CR`. – Stephan Dec 03 '19 at 21:56
  • @Stephan, in this particular case I think the (also default) _space_ delimiter would do the trick anyway since the original code returned `C:` + _space_s + __`, so the __ would disappear anyway... – aschipfl Dec 03 '19 at 22:07