Статья CMD: SetLocal и расширенная обработка команд

Тема в разделе "FAQ по Пакетным файлам CMD/BAT", создана пользователем Dragokas, 27 окт 2013.

  1. Dragokas
    Оффлайн

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    4.476
    Симпатии:
    4.305
    Статья от 10.05.2013
    Автор: Dragokas

    SetLocal, расширенная обработка команд и отложенное раскрытие значения переменной

    Часто встречали такую конструкцию ?
    Код (DOS):
    SetLocal EnableExtensions EnableDelayedExpansion
    По своей сути она состоит из 3 совмещенных частей:
    Код (DOS):
    SetLocal &:: Локализация переменных
    SetLocal EnableExtensions &:: Использование дополнительных ключей
    SetLocal EnableDelayedExpansion &:: Раскрытие переменных через знаки (!)
    SetLocal

    Что делает?
    SetLocal - означает, что все переменные, объявленные внутри Batch-файла, будут локальными и после выхода из него обнуляться.
    Это также оберегает от случаев, когда Вы забываете задавать начальное значение переменной.

    По-умолчанию, значение переменной при инициализации
    для строкового типа = пустой строке,
    для числового типа = 0.

    Если Вы запускаете Batch-файл
    - из CMD.exe (ПУСК -> Выполнить -> CMD -> {Enter})
    - один Batch-файл из другого
    то при повторном запуске без команды SetLocal в переменных останутся старые значения.

    Область видимости переменной, заданной командой Set, является текущая среда интерпретатора, если батник запущен через нее (CMD.exe) (и внутри нет команды локализации SetLocal), или сессия самого батника, если двойным кликом по нему.
    Как задается?
    Код (DOS):
    Переменные, использованные после команды SetLocal, можно обнулить принудительно еще до выхода из Batch-файла командой:
    Код (DOS):
    Конструкция вида:
    Код (DOS):
    SetLocal
    Set B=1
    EndLocal& Set A=%B%
    Позволяет обнулить переменную B, при этом в однострочной команде после EndLocal
    переменная раскрываемая через % и все еще будет содержать старое значение, поэтому может быть "переброшена" через локаль.

    В конструкции вида:
    Код (DOS):
    setLocal EnableDelayedExpansion
    Set B=1
    EndLocal& Set A=!B!
    переменная A получит актуальное (обнуленное) значение переменной B,
    поэтому способ "переброса" значения через локаль невозможно использовать внутри циклов.

    Extensions - режим расширенной обработки команд.

    Что делает?
    Позволяет использовать дополнительные ключи встроенных команд.

    Где используется?
    Откройте справку по командам, например,
    For /?
    Set /?
    Там в первых 10 строках найдете выражение:
    "Если включена расширенная обработка команд... то можно использовать еще и такие ключи..."
    chdir /?
    "Если включена расширенная обработка команд... в таком случае поведение команды изменяется" (касается пробелов в пути).
    ...

    Как включается?
    1) Задается командой
    Код (DOS):
    SetLocal EnableExtensions
    EnableExtensions - обычно включена в системе по-умолчанию.
    Но может быть выключена принудительно через реестр, а также по-умолчанию, выключена в некоторых старых ОС.
    http://technet.microsoft.com/en-us/library/cc959665.aspx
    Поэтому, ее желательно включать во все скрипты.

    2) Через реестр (выше по ссылкам).
    3) Через ключи CMD.exe, если бат-файл или команда запускается через него, а не напрямую.

    Метод может использоваться в однострочных командах, а также методах Shell других ЯП.
    Пример:
    Код (DOS):
    cmd /E:ON /C Commands
    где под Commands подразумевается путь и имя к командному файлу (bat, cmd), цикл, команда, или перечень команд, составленных по правилам формирования однострочных команд Batch.

    Может быть отключена командой:
    Код (DOS):
    SetLocal DisableExtensions
    Практическая польза от отключения, как мне известно, никакой.

    DelayedExpansion - режим отложенного расширения переменных среды.

    Что делает?
    EnableDelayedExpansion - означает возможность использовать восклицательные знаки (!variable!) для раскрытия значения переменной.
    Обычно переменные раскрываются через знак %.
    "Раскрывается" - означает, что мы получаем значение, которое хранит переменная.

    Пример:
    Код (DOS):
    :: Инициализируем переменную и задаем ей значение "Кот"
    set Animal=Кот
    :: Выводим на экран значение переменной Animal
    echo %Animal%
    Необходимость использовать знаки (!) возникает:
    • внутри цикла
    • под скобками
    • в однострочной команде
    *Здесь и далее под конструкцией подразумевается один из указанных выше вариантов.
    Если Вы измените значение переменной внутри конструкции,
    раскрывая переменную через %, Вы получите ее старое значение (присвоенное до входа в эту конструкцию).
    Новое (актуальное) значение переменной можно получить:
    • раскрыв переменную через знаки (!)
    • временно выйдя за пределы конструкции (например, командой Call)
    • после выхода из данной конструкции (ее завершения)
    Как включить возможность использовать (!):
    По-умолчанию, данный режим выключен.

    Включить можно:
    1) командой:
    Код (DOS):
    SetLocal EnableDelayedExpansion
    2) через реестр (на постоянной основе - пользоваться пп.1,3 будет не нужно, но будет работать только на Вашей машине.)
    http://technet.microsoft.com/en-us/library/cc957361.aspx
    3) запуском batch-файла или команд(ы) через специальный ключ CMD.exe:
    Пример:
    Код (DOS):
    cmd /V:ON /C Commands
    где под Commands подразумевается путь и имя к командному файлу (bat, cmd), цикл, команда, или перечень команд, составленных по правилам формирования однострочных команд Batch.
    1) раскрытие переменной через % быстрее, чем через !
    2) при чтении данных из файла, в содержимом которого есть знаки ! и последующей записью или выводом на экран
    этой информации знаки ! "глотаются". Поэтому еще иногда используется команда отключения данного режима:
    Код (DOS):
    SetLocal DisableDelayedExpansion
    3) Когда анализируешь свой же код, удобно понимать логику работы своего алгоритма: если видишь % под циклом, то сразу понятно, что значение этой переменной под циклом не изменяется, а если и изменяется, то в этой же конструкции новое значение не используется.
    1) Цикл:
    Код (DOS):
    @echo off
    SetLocal EnableExtensions EnableDelayedExpansion
    :: Читаем файл example.txt
    :: Заводим счетчик строк count
    :: 5-ю строку файла выводим на экран
    set count=0
    For /F "delims=" %%a in (example.txt) do (
      set /A count+=1
      if !count!==5 echo %%a
      echo В этом месте значение count всегда будет = 0. Count = %count%
      echo А здесь мы получим актуальное значение Count = !Count!
    )
    2) Просто под скобками:
    Код (DOS):
    @echo off
    SetLocal EnableDelayedExpansion
    (
     rem Присвоим значение переменной
      set variable=text
      echo Формируем
      echo несколько
      echo строк
      echo текстового
      echo файла
      echo Здесь ничего не получим. Перед скобками переменной не было присвоено значение.
      echo.%variable%
      echo Здесь получим актуальное значение
      echo !variable!
    ) >> example.txt
    3) В однострочных командах:
    Код (DOS):
    @echo off
    SetLocal EnableDelayedExpansion
    set st1=staraya stroka
    set st1=novaya stroka& echo Здесь получим старую строку %st1%
    set st2=staraya stroka
    set st2=novaya stroka& echo Здесь получим новую строку !st2!
    Ремарка:
    Принцип раскрытия переменных влияет также на изменяемые глобальные переменные, например,
    time и date, которые постоянно обновляются и отображают дату и время.

    После входа в конструкцию эти переменные "замораживаются".
    Чтобы получить актуальную дату/время необходимо раскрытие через знаки (!):
    Код (DOS):
    echo !date! !time!
     
    Последнее редактирование: 2 ноя 2013
    orderman и Kиpилл нравится это.

Поделиться этой страницей