Оператор "FOR"

Давайте заглянем в help по команде FOR.
Есть 4 нотации синтаксиса этого оператора:

Запоминатать не надо, просто обратите внимание, что с директивой usebackq изменилась обработка кавычек, фактически их низвергли до стандартных символов. Это удобно, и позволяет городить вот такие конструкции:
for /f "usebackq delims=*" %%a in (`""%~dp0Tools\findstr.exe" /c:. /r "%EnvFile%""`) do echo "%%a"
и все для того, чтобы нормально передавались пробелы в пути до файла описанного переменнной %EnvFile%.

Ну да ладно, я отвлекся.
Стандартная запись: FOR %variable IN (set) DO command [command-parameters]
Мы говорим ДЛЯ какой переменной, ИЗ какого набора, ЧТО делаем.
И тут все просто:
cd System32
for %a in (????.sys) do echo %a

Логика работы команды FOR во всех режимах одинакова.

  1. То что в скобках преобразуется в построчный список;
  2. Каждая строка сопоставляется с указанной переменной, которая может быть от "a" до "z";
  3. Сопоставленная переменная передается тому, что указано в DO;
Вуаля.
Что-то из разряда бессмысленного:

for %a in ("%Temp%") do echo %a - аналог "echo %Temp%", только сложнее.

  1. Переменная %temp% преобразуется в строку, которая оказывается заключена в кавычки, что формирует собой законченную строку;
  2. Cтрока сопоставляется с переменной "%a";
  3. DO, указывает вывести эту переменную через echo
Давайте что-нибудь по осмысленней придумаем.

for %a in (*.sys) do echo %a %~aa %~ta %~za

  1. Перебираем последовательно все файлы с раширением .sys;
  2. Каждая строка сопоставляется с переменной "a";
  3. Echo выводит %a - то, что сопоставилось, а раз это имя файла, то...
    мы также выведем атрибут файла (%~aa), дату и время его создания (%~ta), а также размер файла (%~za)
    Тильда после % говорит о том, что будет идти модификатор переменной, а не сама переменная;
    Полный список модификаторов можно посмотреть в подсказке команды FOR
FOR /D - я даже рассматривать не буду, потому что все тоже самое, но только вместо файлов, обрабатываются папки.
for /d %a in (*.*) do echo %a %~aa %~ta %~za - помотрите, что выведется.

Едем дальше, потому что сейчас будет само интересное.
FOR /F Давайте подробно остановимся на содержимом скобок, это ключевое и важное для понимая знание:

Стандартный вид:
file-setНабор файлов. Маска,по которой надо выбрать набор файлов, который обрабатывается опциями и отдается на исполнение.
"string"Строка. Это не маска файлов. Это строка, которая обрабатывается опциями и отдается на исполнение.
'command'Это Shell команда, как Dir, например, результат которой будет построчно обрабатан в соответствии с опциями и отдан на исполнение.
Директива в options: "usebackq" кое что меняет в синтаксисе.
file-setНабор файлов. Все тоже самое, как классическом в режиме.
'string'Строка. Если в строке присуствуют двойные кавычки, самое лучшее решение это useback и пробелмы в сторону.
`command`Shell команда. Если в команде есть двойные кавычки, то это самый подходящй выход.

Options
eol=cУказывает ОДИН символ, c которого начинается комментарий. Весьма удобно, если при разборе файла есть строки с комментариями. Символ комментирования будет приводить к пропуску строки, если она будет начинаться с него.
skip=nКоличество строк, которые надо пропустить, перед началом разбора. Полезная штука при выбрасывании всяких заголовков и шапок выводимых некоторыми программами, например, стандартным FIND или командой DIR.
delims=xxxПеречисляем все символы, которые мы хотим использовать в качестве разделителей. Обычно это табуляция и пробел.
tokens=x,y,m-n,*Токен - это временная переменная, которая инициализируется результатом разбора строки. Можно перечислить, номера токенов, которые будут переданы на исполнение, можно указать период от и до какого токена надо передать, и если есть токен "*", то порождается дополнительный токен, который инициализируется, оставшейся не разобранной строкой.
usebackqКоманда изменяющая обработку одиночных и двоичных кавычек в круглых скобках

И перед тем, как начать колдовать, я хочу познакомить вас с еще одной командой, без которой, как без воды, "ни туды и ни сюды".
IF.
Стандартный режим. Command Extension выключен
ERRORLEVEL numberЛюбая программа, после окончания работы, возвращает числовое значение характеризующее код возврата. Обычно это число:
0 - если программа отработала успешно
код ошибки - если у программы, что-то не получилось сделать.
-----
Как такового стандарта на коды ошибок нет. Поэтому рекомендую для каждой утилиты прицениваться, какие коды и в каких случаях возвращаются.
if ERRORLEVEL 0 goto ProgOk
if not ERRORLEVEL 0 goto ProgBad
string1==string2Две строки сравниваются: Если строки содержит числа, то числа преобразуются к числу и эти два числа сравниваются друг с другом на равенство. Если преобразование к числу спотыкается, то сравнение происходит посимвольно и чувствительно к регистру
EXIST filenameЕсли файл или папка с именем "filename" существует.
Стоит помнить, что имена "." и ".." также являются именами файлов, которые обозначают текущую папку и родительскую папку.
if not exist .. echo This is root directory.
if exist .\*.sys echo .sys files presents
Если перед этой командой поставить префикс NOT, то все условия будут работать наоборот.
Расширенный режим. Command Extension включен. По умолчанию он всегда включен.
Некоторые команды начинают обрабатываться иначе.
[/I] string1 compare-op string2Логика такая же, сначала к числам преобразуем, если не получается, то сравниваем строки.
Префикс /I требует от команды сравнивать строки не обращая внимание на регистр. Иными словами, "ABC" будет равно "abc".
Compare-op может быть одним из следующих операторов:
EQUравно
NEQне равно
LSSменьше чем
LEQменьше или равно
GTRбольше чем
GEQбольше или равно
DEFINEDПроверяет на наличие переменной среды.

Вот почти и все. Остальные мелочи, изучим по ходу.
Давайте подсчитаем объем файлов в нашей экспериментально-учениеческой папке.
Самое простое это вызвать команду Dir и посмотреть на предпоследнюю строку, которая описывает число файлов.
Давайте так и сделаем.
Чтобы нам не мешался разделитель сотен и тысяч, мы будем вызывать команду DIR с ключом /-c.
Попробуйте вызывать
dir
А потом
dir /-c.

Теперь попробуем сделать это через команду FOR.
Наша задача выделить количество файлов и занимаемый ими объем.
Чтобы наш код был не зависим от используемой локализации, то я постараюсь избегать решений, явно работающих со сравнением каких либо строк.
Давайте внимательно посмотрим на вывод команды что мы видим в искомой строке ?
Она начинается с числа, потом идет указание, что это число означает, потом суммарный объем.
Если мы посмотрим внмательно, то связка "число строка, число" попадается только 1 раз. Поэтому, если мы будем выяснять является ли токен числом, то мы сможем выбрать нужную нам строку.
У shell есть предел измерения - это число 2147483647, в шестнадцатиричной форме это 0x7FFFFFFF, числа знаковые, поэтому диапазон измерений от -2147483646 до 2147483647. Чисел в понятии shell больше 2147483647 не существует.
В этом легко убедиться посмотрите на результат работы команд:

if 2147483647 equ 2147483647 echo Равно
if 2147483647 equ 2147483648 echo Равно
if 2147483647 equ 2147483646 echo Равно
if 2147483649 GTR 2147483647 echo ...49 больше ...47

Как видно все числа больше 2147483647 оказываются равны 2147483647.
Что нам это дает ?
А то, что никакое число не может быть больше 2147483647. И поэтому если мы сравниваем конструкцией GTR, то никогда не должны получить выполнение условия, если сравниваем с максимальным числом. Не существует числа больше, чем самое большое.
Однако, если мы будем сравнивать не число, то сравнение будет строковым и посимвольным и тогда

if 20.02.2004 GTR 2147483647 echo Больше
if 21.02.2004 GTR 2147483647 echo Больше
if 22.02.2004 GTR 2147483647 echo Больше

странное поведение, да ?
На самом деле в первой строке "20" из "20.02.2004" сравнивается с "21" из "2147483647", во второй "21" с "21" и в третьей "22" с "21". Это можно использовать, но будет громозко и работать будет, как захочет.
Наша первая конструкция на основе "for" кажется более очевидной.
Замечание! Есть такое: стиль программирования, так вот я часто работаю с кавычками, поэтому, чтобы сэкономить время на понимании, где надо мне применять модификатор "usebackq", а где нет, я вместо этого usebackq применяю всегда, это мой стиль программирования.
for /f "usebackq tokens=1-4 skip=5" %a in (`dir /-c`) do echo a=%a b=%b c=%c d=%d

Смотрим на результат, вот как разбирается строка на параметры, мы задали параметр "a", и опиcали, что нам понадобятся токены с 1 по 3ий, и for для нас автоматически создала описанные нами токены: 1ый токен это %a, 2ой %b и 3ий %c, итого, как просили: с 1го по 3ий.
Но допустим, а нас имя файла содержит проблелы, тогда оно будет разобрано не правильно, так как часть имени попадет в параметр "%d" , а остальное вообще потеряется.
В общем случае это не хорошо, лучше не терять, можно не обработать или пропустить, но луше не терять.
Поэтому перепишем нашу команду, так, чтобы она ничего не теряла
for /f "usebackq tokens=1,2,3,4* skip=5" %a in (`dir /-c`) do echo a=%a b=%b c=%c d=%d e=%e

Вот так лучше.
Теперь нам надо выделить последние две строки из всего объема информации.
Можно "нахимичить" применяя IF, сравнивая числа, проверяя на точки, на логическую совместимость параметров и в конце концов, 2мя, 3мя последовательными сравнениями однозначно отсеивать даты, не теряя числа. Но это не красиво и не однозначно.
Разумнее зацепиться за точки в дате, которые точно присуствуют в не нужных нам строках.
Для этого их надо найти. Поиском занимается в утилиты: FIND и FINDSTR. Последняя умеет выводить строки НЕ содержащие поисковый параметр.
Поэтому, если мы каким-нибудь образом, результат команды подадим на вход Findstr, то часть задачи мы выполним.
Можно так:

dir /-c >list.txt - сохраним результат работы команды dir /-c в файл "list.txt", а потом вызовем команду
findstr /v /c:. list.txt
Но во первых это неудобно, во вторых, требует необходимости, где-то сохранять файл, а у нас может не оказаться достаточных прав на его создание, ну и в третьих, это громозко и ко всем прочему, не в одну строчку.
Поэтому сделаем иначе, вспомним о перенаправлении ввода через поток.

dir /-c | findstr /c:. /v

Ключевым моментом здесь является символ перенаправления ввода "|".
Результат отработки команды dir вместо экрана направляется на вход команды "findstr", а та уже за неимением команд перенаправления выводит на экран результат деятельности.
Можно усложнить и отфильтровать вообще все, кроме того, что нужно
dir /-c | findstr /c:. /v | findstr /i /v /c:" c " /c:- /c::

перенаправляя вывод вместо экрана на вход второй команды "findstr /i /v /c:" c " /c:- /c::", мы отбрасываем все, что выводит лишнего команда "dir".
/c:" c "Поиск всех строк содержащих " с ", то есть "c" окруженный пробелами. Это для фильтрации первой строки, выводимой командой dir
/c:-Отфильтровываем все строки содержащие симво минус. Это для фильтрации серийного номера.
/c::Отфильтровываем все строки содержащие двоеточие. Это для фильтрации вывода текущей папки для которой исполняется dir

Путь возможно верный, но не красивый, громозкий и что самое главное, не универсальный, потому что если все будет происходить на диске D:, то /c:" c " не отработает, потому что dir нам покажет строку " d ".
Шаг влево, шаг вправо, грозит сбой. Ну и к тому-же если мы можем сразу пропустить первые 5 строк, то зачем нам надо их фильтровать столь сложным образом ?
Поэтому, возвращаемся к нашей заготовке: for /f "usebackq tokens=1,2,3,4* skip=5" %a in (`dir /-c`) do echo a=%a b=%b c=%c d=%d e=%e и модифицируем ее согласно полученным знаниям, а именно, возьмем от вывода команды dir, только то, что не содержит "." точки пропустив, первые 5 строк.
Так как мы будем использовать команду переопределения вывода, то строку в круглых скобках придется взять в кавычки, однозначно обозначив, таким образом, интерпретатору команду, которую надо выполнить целиком.
for /f "usebackq tokens=1,2,3,4* skip=5" %a in (`"dir /-c | findstr /v /c:."`) do echo a=%a b=%b c=%c d=%d e=%e

Согласитесь, коротко и ясно. Как по написанию, так и по результату.
Всего две строки.
Теперь нам надо взять отсеять одну от другой. Посмотрим, чем отличается одна от другой ? Вторая разбилась на большее количество параметров, чем первая. То есть в ней больше групп символов, которые можно разобрать и раскидать по токенам. Наша строка имеет неопределенным 5ый токен. За это и зацепимся.
IF - не может сравнивать пустые строки. Он выдает ошибку, что приводит к завершению выполнения блока команд или всего пакетного файла.
Поэтому воспользуемся простым способом сравнения, путем добавления лишнего символа к сравниваемой строке.
If то_что_может_оказаться_пустым.==. - Добавляя точку к концу или к началу сравниваемой строки, мы гарантируем, что if никогда не столкнется с ситуацией, когда ей нечего сравнивать, а нам это дает возможность обработать ситуацию, отловить, когда сравнение вдруг обезсмысливается.
for /f "usebackq tokens=1,2,3,4* skip=5" %a in (`"dir /-c | findstr /v /c:."`) do if %e.==. echo a=%a b=%b c=%c d=%d e=%e

Ну как вам ?
Коротко и просто.
Можно чуть украсить вывод:

for /f "usebackq tokens=1,2,3,4* skip=5" %a in (`"dir /-c | findstr /v /c:."`) do if %e.==. echo Total files is %a sized %c bytes Если вы вырабатываете какой-нибудь отчет, то перенаправив вывод команды echo сможете получить симпатичный отчет об объеме всех файлов.
Блоки команд. Переменные окружения.>>>>>

Hosted by uCoz