Been a while since I posted here, and while the following is something trivial it is nevertheless something I had to Google a bit to find out, so here goes.
I have a lot of micro SD cards to which I sync my music. The cards are labelled “Card1”, “Card2”, and so on. Corresponding to these I have folders called “Card1”, “Card2”, and so on. I have a batch file that runs robocopy to copy from the folder to card. I have to specify the drive letter of the card to the batch file, but now I am being lazy and want to just double click the batch file and get it to figure out the drive letter. After all the drive with a label “CardX” will be the one I want to use.
How can I get the drive letter from the label? There are many ways probably, since I like WMIC here’s how I will do it:
1 |
wmic volume |
This command will list all the volumes on the computer. There’s a lot of output, so a better way is to use the /format:list
switch to get a listed output:
1 |
wmic volume get /format:list |
Here’s an example output for my micro SD card:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
Access= Automount=TRUE Availability= BlockSize=131072 BootVolume=FALSE Capacity=62724767744 Caption=E:\ Compressed= ConfigManagerErrorCode= ConfigManagerUserConfig= CreationClassName= Description= DeviceID=\\?\Volume{ccc55992-18dc-11e4-beaf-c417feeee1af}\ DirtyBitSet=FALSE DriveLetter=E: DriveType=2 ErrorCleared= ErrorDescription= ErrorMethodology= FileSystem=exFAT FreeSpace=4087218176 IndexingEnabled= InstallDate= Label=CARD4 LastErrorCode= MaximumFileNameLength=255 Name=E:\ NumberOfBlocks= PageFilePresent=FALSE PNPDeviceID= PowerManagementCapabilities= PowerManagementSupported= Purpose= QuotasEnabled= QuotasIncomplete= QuotasRebuilding= SerialNumber=1721549728 Status= StatusInfo= SupportsDiskQuotas=FALSE SupportsFileBasedCompression=FALSE SystemCreationClassName= SystemName=TINTIN SystemVolume=FALSE |
It’s easy to see that the Label
property can be used to check the label. The DriveLetter
property gives me the drive name. If I want to target removable disks only (as is my case) the DriveType
property can be used.
Thus for instance, to filter by the label I can do:
1 |
wmic volume where "Label='Card4'" |
Or to filter by both label and type I can do:
1 |
wmic volume where "Label='Card4' and DriveType=2" |
To output only the drive letter, I can use the get
verb of WMIC:
1 2 3 4 5 6 7 8 |
C:\Users\rakhesh>wmic volume where "Label='Card4' and DriveType=2" get DriveLetter DriveLetter E: C:\Users\rakhesh>wmic volume where "Label='Card4' and DriveType=2" get DriveLetter /format:list DriveLetter=E: |
The second command is what I will use further as it returns the output in a way I know how to use.
In batch files the FOR
loop can be used to parse output and do things with it. The best place to get start with is by typing help for
in a command prompt to get the help text. Here’s the bit that caught my attention:
Finally, you can use the FOR /F command to parse the output of a
command. You do this by making the file-set between the
parenthesis a back quoted string. It will be treated as a command
line, which is passed to a child CMD.EXE and the output is captured
into memory and parsed as if it was a file. So the following
example:FOR /F “usebackq delims==” %i IN (
set
) DO @echo %iwould enumerate the environment variable names in the current
environment.
This looks like what I want. The usebackq
option tells FOR
that the text between the back-ticks –
in the example above – is to be treated like a command and the output of that is to be parsed. The set
delims==
option tells FOR
that the delimiter between parts of the output is the =
character. In case of the example above, since the output of set
is a series of text of the form VARIABLE=VALUE
, this text will be split along the =
character and the %i
variable will be assigned the part on the left. So the snippet above will output a list of VARIABLE
s.
If I adapt that command to my command above, I have the following:
1 |
FOR /F "usebackq delims==" %i IN (`wmic volume where "Label='Card4' and DriveType=2" get DriveLetter /format:list`) DO @echo %i |
Output from the above code looks like this:
1 2 3 4 5 6 |
ECHO is on. ECHO is on. DriveLetter ECHO is on. ECHO is on. ECHO is on. |
As expected, the picks the DriveLetter
part. What I want instead is the bit on the right hand side, so I use the tokens
option for that. I want the second token, so I use tokens=2
. I learnt about this from the FOR
help page.
Here’s the final command:
1 |
FOR /F "tokens=2 usebackq delims==" %i IN (`wmic volume where "Label='Card4' and DriveType=2" get DriveLetter /format:list`) DO @echo %i |
That’s it! Now to assign this to a variable I do change the echo
to a variable assignment:
1 |
FOR /F "tokens=2 usebackq delims==" %i IN (`wmic volume where "Label='Card4' and DriveType=2" get DriveLetter /format:list`) DO set CARD_DRIVE=%i |
Here’s the final result in a batch file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
SET /P INP=Which card? Type digit and press ENTER: SET SOURCE=Card%INP% FOR /F "tokens=2 usebackq delims==" %%i IN (`wmic volume where "Label='%SOURCE%' and DriveType=2" get DriveLetter /format:list`) DO set DEST=%%i IF "%DEST%"=="" GOTO WrongCard robocopy %SOURCE% %DEST% GOTO TheEnd :WrongCard ECHO Error: Card not found! GOTO TheEnd :TheEnd |