По сути подавляющее большинство батников представляет собой циклическую обработку результатов вывода команды, содержащего нам нужную информацию. К сожалению вывод команды редко дает сразу нужный результат в нужном виде, поэтому фильтровать вывод необходимо. В качестве примера будем определять букву системного диска из реестра Windows 7/Windows XP.
Буква системного диска находится в реестре в кусте
HKEY_CURRENT_USER\Volatile Environment, строковый (
REG_SZ) параметр
HOMEDRIVE. Определим значение этого параметра при помощи утилиты командной строки
reg.exe, синтаксис которой можно посмотреть в справке
reg.exe /?.
Результат вывода в WinXP:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE
! REG.EXE VERSION 3.0
HKEY_CURRENT_USER\Volatile Environment
HOMEDRIVE REG_SZ C:
c:\temp>
Результат вывода в Win7:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE
HKEY_CURRENT_USER\Volatile Environment
HOMEDRIVE REG_SZ C:
c:\temp>
Видите разницу в выводах одной и той же команды? Количество строк неодинаково и строка с версией
reg.exe в выводе для WinXP. Дело в разных версиях
reg.exe в Win7 и WinXP, формирующих свой вывод по-разному, поэтому дальнейший разбор вывода командой
for с указанием пропуска первых 4 строк вывода
skip=4 на Win7 закончится ничем -
for пропустит нужную нам строку. Вывод: результат нужно фильтровать, выделив нужную строку. Сделать это можно, используя команды
find или
findstr, перенаправив результат
reg на вход команды
find или
findstr при помощи оператора piping (|). Используем
find:
Результат вывода:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE|find "REG_SZ"
HOMEDRIVE REG_SZ C:
c:\temp>
"REG_SZ" - ищем строку с буквой по чему-нибудь, что отличает искомую строку от всех остальных. Все, строка найдена, причем независимо от ОС результат будет одинаковым.
Кстати, заменим
Find "REG_SZ" на команду
Findstr /N $ и посмотрим, на результат в WinXP и Win7. Параметр
/N пронумерует обрабатываемые строки, а
$ - шаблон для поиска, означающий, что будет произведен поиск строк, заканчивающихся на символ конца строки, а это все строки, включая пустые, т.е. просто посмотрим сколько строк вернет
reg.exe в разных версиях Windows.
Результат вывода в WinXP:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE|findstr /n $
1:
2:! REG.EXE VERSION 3.0
3:
4:HKEY_CURRENT_USER\Volatile Environment
5: HOMEDRIVE REG_SZ C:
6:
c:\temp>
Результат вывода в Win7:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE|findstr /n $
1:
2:HKEY_CURRENT_USER\Volatile Environment
3: HOMEDRIVE REG_SZ C:
4:
c:\temp>
Теперь видите, почему
for с
"skip=4" для WinXP получит искомую строку, а Win7 нет? Поэтому мы и пропустили результат
reg через
find. Но это не все. Что будет, если запрашиваемого параметра нет или куст указан несуществующий? Внесем изменения, добавив к
HOMEDRIVE любой символ, например 1.
Результат вывода в WinXP:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE1|find "REG_SZ"
Ошибка: Системе не удалось найти указанный раздел или параметр реестра
c:\temp>
Результат вывода в Win7:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE1|find "REG_SZ"
Ошибка: Не удается найти указанный раздел или параметр в реестре.
c:\temp>
В
for это сообщение для обработки даже не попадет, т.к. принадлежит потоку StdErr команды
reg,
for же работает с
StdOut, потоком, выводящим результат на экран в случае успешной отработки команды. Выход - перенаправить
StdErr не на экран (значение по умолчанию), а в устройство
nul, т.е. в никуда:
Результат вывода
:
Код:

c:\temp>reg query "HKCU\Volatile Environment" /v HOMEDRIVE1 2>nul|find "REG_SZ"
c:\temp>
, где
2>nul и есть перенаправление
StdErr (дескриптор потока
StdErr равен 2,
StdOut равен 1) в никуда. На экране ничего, хотя параметра HOMEDRIVE1 не существует.
Итак, строка найдена, теперь остается отделить букву диска от ненужных HOMEDRIVE, REG_SZ и пробелов. Для этого и нужна команда
for, которая с параметром
/f позволяет работать с результатом вывода других команд. Взглянем на нашу строку:
" HOMEDRIVE REG_SZ C:" (привел в кавычках). Ее можно представить как строку с 3 подстроками (словами), разделенных пробелами. Осталось только указать
for-у ключ разбора строки
tokens=3 - делить строку на 3 части, 3-я подстрока в переменную (ключ
delims (символ разделителя подстрок) не нужен, т.к. символы пробела и табуляции используется по умолчанию в качестве разделителей, а подстроки в нашей строке отделены пробелами) и вывести результат на экран или присвоить какой-либо переменной.
Результат вывода:
Код:

c:\temp>for /f "tokens=3" %a in ('reg query "HKCU\Volatile Environment" /v HOMEDRIVE 2>nul|find "REG_SZ"') do set drive=%a
Непредвиденное появление: 2>.
c:\temp>
Вот так облом, совсем не то, что ожидали увидеть, ведь интерпретатор решил, что была предпринята попытка перенаправления
StdErr, а синтаксис
for-а не закончился и нарушился. Чтобы указать интерпретатору, что символ
> (как и
|) являются частью синтаксиса
for, а не попыткой перенаправления (
>) или piping-а (
|), нужно экранировать эти спецсимволы символом
^:
Результат вывода:
Код:

c:\temp>for /f "tokens=3" %a in ('reg query "HKCU\Volatile Environment" /v HOMEDRIVE 2^>nul^|find "REG_SZ"') do set drive=%a
c:\temp>set drive=C:
c:\temp>
Все, переменная drive теперь содержит букву диска.