MyTetra Share
Делитесь знаниями!
Основы BAT файлов
Время создания: 12.07.2012 11:40
Автор: Xintrea
Текстовые метки: windows, bat
Раздел: Компьютер - Windows - BAT файлы, командная строка
Запись: xintrea/mytetra_syncro/master/base/1342078818edarb08zy6/text.html на raw.github.com

В этой статье:


  • Определение переменных
  • Переменные командной строки (параметры вызова bat-файла)
  • Оператор условия IF
  • Функции
  • Использование возвращаемых значений (обработка кода завершения программы)


Определение переменных


SET <Имяпеременной>=<Значениепеременной>


Оператор SET представляет собой расширение возможностей работы с параметрами в операционной системе. Он задает переменную, значение которой подставляется вместо ее имени при любом использовании этого имени между знаками процента. Так, если задано (переменная, которую требуют многие игры, использующие звуковую карту компьютера):


SET BLASTER=A220 I5 D1 P330


то при использовании в пакетном файле следующей конструкции:


ECHO %BLASTER%


на экран будет выведено "A220 I5 D1 P330". Переменные, определенные с помощью оператора SET называются переменными окружения среды (environment) и являются видимыми после выполнения до перезапуска DOS (если не изменять ее вручную в памяти). То есть, ее можно использовать из одного пакетного файла или программы после задания в другом. Наиболее известной является переменная PATH, представляющая собой набор путей для быстрого поиска файлов. Она задается в файле autoexec.bat.



Переменные командной строки
(параметры вызова bat-файла)


%<цифра 0-9>


Как и в любом языке, в языке пакетных файлов возможно использование переменных, полученных в качестве параметров bat-файла.


Всего может быть 10 одновременно существующих независимых переменных. Для написания сложных программ это довольно мало, хотя для обычной работы часто хватает и 3-4. Значение переменной равно значению соответствующего параметра из командной строки. Переменная %0 будет содержать имя .bat-файла и, если вы указали, путь к нему. То есть, если вы запустили файл abc.bat со следующими параметрами:


abc.bat a bc def


то переменная %0 будет содержать значение abc.bat, %1 будет содержать значение a, %2 будет содержать bc, а %3 - def. Это свойство широко используется для создания универсальных пакетных файлов при работе с повторяющимися операциями.


Чтобы получить более чем 10 переменных из командной строки, можно воспользоваться командой SHIFT.


Команда SHIFT позволяет использовать число параметров командной строки далее 10. Однако, при этом теряются соответственно более ранние параметры. Иными словами, команда SHIFT сдвигает все значения переменных на один шаг влево. То есть, переменная %0 будет содержать значение, содержавшееся до этого в переменной %1, а переменная %1 - значение переменной %2 до сдвига. Однако, данная операция является необратимой, то есть, невозможно сдвинуть переменные обратно.



Оператор условия IF


К счастью, командный интерпретатор cmd.exe современных ОС Windows 2000 и старше поддерживает блоки команд в конструкциях ветвления, что устраняет необходимость применения IF с метками. Блоки команд заключаются в круглые скобки. Выглядит это так (имитируя C/C++ indentation style):


if condition (

rem Команды ветки ‘then’

rem ...

) else (

rem Команды ветки ‘else’

rem ...

)


Конкретный пример использования:


@echo off


set BUILDMODE=%1


if "%BUILDMODE%" == "" (

echo FAIL: Аргумент является обязательным ^(--debug, --release^)

exit /b 1

)


rem Удаляем из аргумента все дефисы для упрощения обработки

set BUILDMODE=%BUILDMODE:-=%


if "%BUILDMODE%" == "debug" (

echo INFO: Устанавливаем debug-режим окружения

set CCFLAGS=/Od /MDd /Z7

) else (

echo INFO: Устанавливаем release-режим окружения

set CCFLAGS=/O2 /MD

)


На мой взгляд, с этим уже вполне можно жить. Но, как всегда, жизнь не так проста, как кажется. Есть одна проблема. Переменные, использующиеся в блоках then и else, раскрываются перед началом выполнения этих блоков, а не в процессе выполнения. В приведенном примере это не вызывает никаких проблем, однако в следующем вызовет:


if "%BUILDMODE%" == "debug" (

echo INFO: Устанавливаем debug-режим окружения

set OPTFLAGS=/Od

set CCFLAGS=%OPTFLAGS% /MDd /Z7

) else (

echo INFO: Устанавливаем release-режим окружения

set OPTFLAGS=/O2

set CCFLAGS=%OPTFLAGS% /MD

)


Загвоздка в том, что в обоих блоках подстановка переменной OPTFLAGS произойдет до того, как она будет изменена в процессе выполнения этого блока. Соответственно, в CCFLAGS будет подставлено то значение, которое OPTFLAGS имела на момент начала выполнения данного if-блока.


Решается эта проблема путем использования отложенного раскрытия переменных. Переменные, заключенные в !…! вместо %…%, будут раскрыты в их значения только в момент непосредственного использования. Данный режим по умолчанию отключен. Включить его можно либо использованием ключа /V:ON при вызове cmd.exe, либо использованием команды:


setlocal enabledelayedexpansion



в тексте самого bat-файла. Второй способ мне представляется более удобным – не очень здорово требовать от кого-то запуска твоего сценария с определенным параметром.


С учетом сказанного предыдущий «неправильный» пример может быть исправлен так:


setlocal enabledelayedexpansion


if "%BUILDMODE%" == "debug" (

echo INFO: Setting up debug mode environment

set OPTFLAGS=/Od

set CCFLAGS=!OPTFLAGS! /MDd /Z7

) else (

echo INFO: Setting up release mode environment

set OPTFLAGS=/O2

set CCFLAGS=!OPTFLAGS! /MD

)


Вот теперь это почти полноценный if-then-else блок. Почти, потому что если в одной из команд echo у вас встретится закрывающая круглая скобка, то вам необходимо заэкранировать ее символом ^, иначе синтаксический анализатор путается…


Но в любом случае, это гораздо лучше безумного количества меток и переходов.



Функции


А можно создать в bat-файле функцию? Да, можно. Более того, иногда даже нужно. Правда, функциями это можно назвать условно.


Есть особый синтаксис команды call, который позволяет перейти на метку в этом же bat-файле с запоминанием места, откуда был произведен этот вызов:


call :метка аргументы


Возврат из функции производится командой:


exit /b [опциональный код возврата]


Ключ /b здесь очень важен: без него будет произведен выход не из функции, а из сценария вообще.


За подробностями наберите в командной строке:


call /?

exit /?


Что интересно, команда call с таким синтаксисом поддерживает рекурсивные вызовы с автоматическим созданием нового фрейма для переменных аргументов %0-%9. Иногда это может быть полезным. Вот классический пример рекурсивного подсчета факториала на командном языке:


@echo off


call :factorial %1

echo %RESULT%

exit


rem Функция для подсчета значения факториала

rem Вход:

rem %1 Число, для которого необходимо подсчитать факториал

rem Выход:

rem %RESULT% Значение факториала

:factorial


if %1 == 0 (

set RESULT=1

exit /b

)


if %1 == 1 (

set RESULT=1

exit /b

)


set /a PARAM=%1 - 1


call :factorial %PARAM%


set /a RESULT=%1 * %RESULT%


exit /b


Пример работы:


> factorial.bat 10

3628800



Использование возвращаемых значений
(обработка кода завершения программы)


Любая программа при завершении своей работы возвращает операционной системе код своего завершения. Принято при успешном завершении возвращать ноль, иначе - код ошибки. Иногда, или, вернее, часто, программа "сознательно" возвращает ненулевое значение для того, чтобы в пакетном файле можно было "узнать" некоторые подробности ее работы. Например, программа возвращает код нажатой клавиши, а .bat-файл по нему выполняет различные действия.


Каким же образом пакетный файл может узнать код завершения выполненной программы? Для этого предусмотрено ключевая переменная ERRORLEVEL.


Пример пакетного файла с errorlevel'ами:


@ECHO OFF

REM Запускаем программу prg1.exe

PRG1.EXE

REM Анализ кода завершения

IF ERRORLEVEL 2 GOTO FILENOTFOUND

IF ERRORLEVEL 1 GOTO WRITEERROR

IF ERRORLEVEL 0 GOTO EXITOK

GOTO ONEXIT

:FILENOTFOUND

ECHO Ошибка! Файл не найден!

GOTO ONEXIT

:WRITEERROR

ECHO Ошибка записи!

GOTO ONEXIT

:EXITOK

ECHO Программа завершена благополучно.

GOTO ONEXIT

:ONEXIT


Обратите внимание - анализ кода завершения начинается не с нуля, а с максимально возможного значения. Дело в том, что подобная проверка означает: "если errorlevel больше или равен значению, то...". То есть, если мы будем проверять, начиная с нуля, любое значение будет истинным на первой же строке, что неверно.


Это самая распространенная ошибка в подобного рода программах.


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования