Тема: CMD/BAT: Условные операторы на стероидах
Необходимое вступление
В конце прошлого года я решил обновить старый и давно заброшенный проект, который предполагался быть коллекцией каких-то полезных наработок по пакетным файлам, но так им и не стал. На этот раз я решил попробовать улучшить условные операторы, видоизменить с целью повышения их полезности, гибкости и мощности.
В основу улучшений легла встроенная функция test из unix shell. Именно они и были названы "стероидами".
Не все условные выражения test реализованы. Некоторые и них работают только при определенных условиях. Было добавлено несколько собственных решений.
В процесе разработки строго соблюдалось правило - использовать только внутренние команды интерпретатора CMD.EXE. Следование этому правилу не повлияло на реализацию условных выражений.
Работа носила академический интерес, но результаты могут быть интересны в использовании на практике.
Ссылка на скачивание
К сожалению, лаконично писать я не умею, поэтому помещаю ссылку поближе к началу, чтобы она не затерялась и заинтересованные могли ее быстро найти.
https://github.com/ildar-shaimordanov/c … r/when.bat
Стандартный оператор IF
Стандарная форма условного оператора весьма ограничена.
if EXPR (
DO_THEN
) else (
DO_ELSE
)
Она фактически не умеет вычислять более сложные логические выражения вида EXPR1 and EXPR2 ... или EXPR1 or EXPR2 .... В общем случае это либо классические решения с использованием меток, либо сокращенные версии вида if EXPR1 if EXPR2 DO_THEN.
Есть несколько случаев, когда простая проверка реализована в виде громоздкой конструкции с использованием циклов (проверка атрибутов или свойств файла). Данное решение скрывает эти недостатки и делает все условные проверки единообразными.
Условный оператор на "стероидах"
Общая форма "стероидов":
call when :if EXPR && DO_THEN
Основа - стрипт when.bat. Он содержит две "функции" (функция - в терминах пакетных скриптов). :if вычисляет условное выражение и возвращает (0), если выражение верно, иначе (1). Возвращает код (2), в случае неправильных аргументов.
:unless аналогично :if, но смысл проверки противоположен.
Аналогично встроенной команде IF функция вычисляет одно простое логческое выражение. Но, благодаря тому, что они возвращают статус их можно объединять в более сложные команды, эмулируя тем самым составные логические выражения. Следующие примеры несколько искусственные, но они иллюстрируют сказанное:
:: if "%PROCESSOR_ARCHITEW6432%" != "" && "%PROCESSOR_ARCHITECTURE%" == "x86" (
:: )
(
call when :if -n "%PROCESSOR_ARCHITEW6432%" && call test :if "%PROCESSOR_ARCHITECTURE%" == "x86"
) && (
echo режим эмуляции
)
:: if "%PROCESSOR_ARCHITEW6432%" == "AMD64" || "%PROCESSOR_ARCHITEW6432%" == "IA64" && "%PROCESSOR_ARCHITECTURE%" == "x86" (
:: )
(
call when :if "%PROCESSOR_ARCHITEW6432%" == "AMD64" || call test :if "%PROCESSOR_ARCHITEW6432%" == "IA64"
) && (
call when :if "%PROCESSOR_ARCHITECTURE%" == "x86"
) && (
echo режим эмуляции
)
Псевдокод в комментариях к каждому примеру показывает какой вариант условного оператора эмулируется, если бы он был реализован.
Благодаря тому, что используется статус завершения (0 или 1) эти команды можно комбинировать с другими командами, реализуя достаточно сложные условные проверки.
Так как это внешний скрипт, его можно поместить в один из каталогов, описанных в переменной окружения %PATH%, и тогда скрипт будет доступен во всей системе.
Чтобы встроить и использовать его в своих скриптах без вызова внешнего скрипта достаточно выполнить следующую команду, которая встроит тело скрипта в основной (в примере filename):
call when APPEND-TO filename
После этого функции :if и :unless будут доступны напрямую, по метке, без вызова внешноего скрипта:
(
call :if -n "%PROCESSOR_ARCHITEW6432%" && call :if "%PROCESSOR_ARCHITECTURE%" == "x86"
) && (
echo режим эмуляции
)
Расширенные файловые операторы
-a FILE
Верно, если файл существует.
-b FILE
Верно, если аргумент - дисковое устройство.
-c FILE
Верно, если аргумент - символьное устройство.
-d FILE
Верно, если аргумент - каталог. Аналогично -attr d.
-e FILE
Верно, если файл существует.
-f FILE
Верно, если аргумент - обычный файл.
-h FILE
Верно, если аргумент - ссылка. Аналогично -attr l.
-L FILE
Верно, если аргумент - ссылка. Аналогично -attr l.
-r FILE
Верно, если файл имеет атрибут только чтение. Аналогично -attr r.
-s FILE
Верно, если файл существует и непустой.
-w FILE
Верно, если файл доступен на запись, например, не установлен атрибут только чтение.
-x FILE
Верно, если файл исполнимый.
-attr ATTR FILE
Верно, если установлен атрибут файла.
Доступные следующие атрибуты:
Attribute Expansion
FILE_ATTRIBUTE_DIRECTORY d--------
FILE_ATTRIBUTE_READONLY -r-------
FILE_ATTRIBUTE_ARCHIVE --a------
FILE_ATTRIBUTE_HIDDEN ---h-----
FILE_ATTRIBUTE_SYSTEM ----s----
FILE_ATTRIBUTE_COMPRESSED -----c---
FILE_ATTRIBUTE_OFFLINE ------o--
FILE_ATTRIBUTE_TEMPORARY -------t-
FILE_ATTRIBUTE_REPARSE_POINT --------l
FILE_ATTRIBUTE_NORMAL ---------
-path FILE
Верно, если файл есть в одном из каталогов переменной окружения PATH.
Еще файловых операторов
FILE1 -nt FILE2
Верно, если FILE1 новее чем FILE2 (в соответствии с временем модификации файла). Этот оператор зависит от пользовательских и региональных настроек. Это значит, что в общем случае, сравнение не может быть надежным.
FILE1 -ot FILE2
Верно, если FILE1 старее чем FILE2 (в соответствии с временем модификации файла). Этот оператор зависит от пользовательских и региональных настроек. Это значит, что в общем случае, сравнение не может быть надежным.
Расширенные строковые операторы
-n STRING
Верно, если строка непустая.
-z STRING
Верно, если строка пустая.
Еще строковых операторов
STACK -contains NEEDLE
Верно, если STACK содержит NEEDLE.
STACK -starts NEEDLE
Верно, если STACK начинается с NEEDLE.
STACK -ends NEEDLE
Вернл, если STACK завершается NEEDLE.

