После того как администратор создал и успешно запустил свой первый простой сценарий командной строки (скажем, для диагностики сервера с помощью утилиты ping), он задумывается о том, как сделать так, чтобы было удобно повторно использовать данный сценарий при тестировании другого сервера или группы серверов. В результате он может прийти к выводу, что наилучшим решением было бы предусмотреть возможность ввода в сценарий некоторых входных данных, которые можно изменять. Если жестко запрограммировать эти входные данные, то при каждом их изменении придется соответствующим образом редактировать код сценария. Например, если явно задать имя компьютера, на котором требуется выполнить те или иные операции, то перед каждым запуском сценария на другом компьютере придется редактировать код. Данный подход не просто неудобен, он может послужить причиной непреднамеренного изменения кода сценария и, соответственно, привести к его некорректной работе. Предпочтительнее сохранить код сценария «в неприкосновенности» после его отладки, что обеспечит его нормальную работу в дальнейшем.

Если входные данные, которые предполагается передавать сценарию, имеют незначительный объем, тогда весьма эффективным решением для организации их ввода будет использование аргументов командной строки. Создав сценарий, управляемый аргументами, впоследствии можно легко преобразовать его для использования других технологий ввода данных в соответствии с новыми требованиями. Альтернативные технологии ввода данных рассматриваются во врезке «Возможные способы ввода данных». Чтобы помочь читателям разобраться в том, как работать с аргументами командной строки и избегать типичных ошибок, я собрал в данной статье несколько наиболее часто задаваемых вопросов

В. Одна из часто используемых мною утилит требует указания около 10 различных ключей и параметров. Поэтому перед каждым ее запуском мне приходится просматривать справочную систему и вспоминать, какой именно синтаксис вызова я использовал в последний раз. Я написал специальный сценарий, который мне приходится каждый раз редактировать. При этом я обнаружил, что фактически требуется изменять только три параметра. Могу ли я использовать аргументы командной строки для передачи этих параметров сценарию, когда мне нужно в очередной раз запустить данную утилиту?

О. Создание сценариев для запуска из них утилит пакета Resource Kit или программ независимых разработчиков — прекрасная возможность для применения аргументов командной строки, особенно в тех случаях, когда запускаемая программа имеет строку вызова, содержащую несколько сложных ключей. Причем в большинстве случаев утилита, скорее всего, запускается с одним и тем же набором ключей. Я, например, для переноса больших объемов данных часто пользуюсь утилитой Robocopy (из набора Microsoft Windows Resource Kit) — программой, имеющей множество различных ключей запуска. Если создать сценарий, который будет выполнять большую часть операций, реализуемых программой, можно, во-первых, сэкономить время, а во-вторых, гарантировать точность результатов работы данной утилиты. Для этого нужно просто прописать в сценарии те ключи, которые вы обычно не изменяете, и передавать ему в виде аргументов значения тех ключей, которые приходится изменять часто. Однако при этом следует понимать, что случайное добавление и удаление каких-либо ключей при работе с Robocopy может привести к неприятным последствиям — например, могут быть перемещены какие-то важные файлы, которые предполагалось только скопировать, либо пунктом назначения для файлов оказался NTFS-ресурс, к которому отсутствуют необходимые разрешения доступа.

В листинге 1 показан сценарий RoboArg.bat, который представляет собой пример запуска утилиты Robocopy. При запуске сценария из командной строки ему должны быть переданы два аргумента. Ниже приведена строка запуска этого сценария:

RoboArg.bat "C:sourcefiles" 
"D:destinationfiles"

где C:sourcefiles — путь к файлам, которые требуется скопировать, а D:destinationfiles указывает местоположение каталога, в который нужно скопировать данные файлы.

В среде Windows существует специальная группа переменных окружения для поддержки работы с аргументами сценариев командной строки: они имеют обозначения от %0 до %9. Эти переменные могут использоваться для передачи входной информации сценарию при его выполнении. При этом переменная %1 определяет первый аргумент, вводимый в командной строке, переменная %2 — второй и т. д. Таким образом, в сценарии RoboArg.bat переменными %1 и %2 определяются соответственно исходный и конечный файлы.

В начале сценария RoboArg.bat выполняют две процедуры проверки, чтобы удостовериться в том, что было введено правильное количество аргументов. В первой из них используется команда IF, с помощью которой значение аргумента %2 сравнивается с пустой строкой. При выявлении совпадения выводится предупреждение о том, что введено недостаточное количество аргументов, после чего сценарий завершает работу. Вторая проверка заключается в том, что с помощью оператора GTR (что означает «больше, чем», т. е. это эквивалентно символу «>») определяется, содержит ли переменная %3 какое-либо значение. Оператор GTR служит для сравнения двух величин. Если первая величина больше, чем вторая, то результатом сравнения будет TRUE и будут выполняться те команды, которые следуют в данной строке за оператором сравнения. Если же первая величина не больше второй, то результатом сравнения будет FALSE, поэтому исполнительный механизм обработки сценария не будет выполнять остальные команды, имеющиеся в этой строке, а перейдет к обработке следующей строки сценария. Хотя оператор GTR обычно используется как математический, здесь я применил его для проверки существования значений. При создании сценариев командной строки проверка того, содержит ли некоторая переменная какое-либо значение, всегда является более надежной, чем попытка убедиться, что эта переменная не содержит ничего. Если переменная %3 является пустой, то ее содержимое не может быть больше 1, тогда сценарий игнорирует оставшиеся в этой строке команды и переходит к следующей строке, в которой производится запуск утилиты Robocopy. Если же переменная %3 имеет не пустое значение, то эта величина будет больше 1, поэтому данная строка будет обработана полностью, в результате чего будет выведено сообщение Too many arguments («Слишком много аргументов»), а затем сценарий завершит работу. Несколько других подходов к обработке аргументов кратко рассматриваются во врезке «Методы работы с аргументами».

В. Я понимаю, что переменные %1 и %2 соответствуют первому и второму аргументу. А имеет ли какое-либо назначение переменная %0?

О. Да, переменная %0 определяет путь к сценарию. Чтобы увидеть использование переменной %0 в действии, следует запустить сценарий TestVar.bat, показанный в листинге 2.

Возможность получения данных о каталоге размещения сценария является весьма полезной. Допустим, требуется, чтобы сценарий сам определял местонахождение других используемых файлов (таких, как утилиты, входные и выходные файлы). В этом случае для получения информации о размещении можно задействовать переменную %0 в сочетании с командой CALL. После этого сценарий можно разместить на любом сервере и в любом каталоге, и он будет корректно работать, причем изменения в него вносить не придется. В листинге 3 показан пример сценария Test0Var.bat, в котором имеется процедура CALL, которую можно применить для реализации подобной функции автопоиска.

В данном примере использование параметра командного файла %∼dp1 демонстрирует возможность подстановки параметров, которая весьма полезна во многих операциях, выполняемых в сценариях. В табл. 1 перечислено несколько вариантов использования параметров командного файла. Обратите внимание, что %∼dp1 представляет собой комбинацию параметров %∼d1 и %∼p1, каждый из которых определяет соответственно букву, обозначающую диск, и путь. Полный перечень вариантов использования этих параметров можно увидеть, запустив команду CALL с ключом /?.

В. Если использовать для определения местонахождения .bat-файла не сочетание параметров командного файла %∼dp1, а переменную окружения %CD%, то не будет ли это более простым решением?

О. С помощью переменной %CD% можно определить место, из которого запускается сценарий. Но это место не обязательно должно соответствовать тому каталогу, в котором он размещается.

В. Я знаю, что аргументам сценария могут соответствовать только девять переменных (от %1 до %9). Каково максимальное количество символов и аргументов, которое я могу ввести в командной строке?

О. Максимальное количество вводимых символов будет зависеть от типа используемой операционной системы и от пути к сценарию, длина которого тоже будет иметь значение для максимального количества символов, которые могут быть введены в командной строке. В Windows 2000 это значение соответствует примерно 2045 символам и пробелам. Однако, если вы собираетесь вводить столь значительное число символов в командной строке, будьте готовы к тому, что придется выполнять проверку корректности введенной информации. Также следует иметь в виду, что оболочка командной строки не всегда выводит сообщение об ошибке при превышении максимального количества символов. Если вам все же необходимо использовать очень длинные строки ввода или большое количество этих строк, советую размещать их во входном файле, который затем обрабатывать сценарием.

Что касается вопроса о максимальном количестве аргументов, то здесь единственным ограничением будет максимальное количество символов и разделителей (т.е. намного больше, чем нужно). В обычной ситуации вам доступны только девять аргументов, однако с помощью команды SHIFT можно задействовать дополнительные аргументы. Для получения более подробной информации о синтаксисе этой команды следует запустить ее в виде SHIFT /?.

В листинге 4 показан сценарий TestLotsOfArgs.bat script, в котором приводится пример обработки неограниченного количества аргументов. Данный код также демонстрирует, как можно обнаруживать, что никаких аргументов вводить не требуется. В данном примере выполняется запуск утилиты ping для каждого аргумента server-name.

В. При запуске утилиты DSQuery я попытался указать в качестве аргумента строку ADsPath, однако в таком виде она не работает. Синтаксис запуска сценария выглядел следующим образом:

MyScript.bat ou=server,dc=sales,dc=mycompany, dc=com
Что я сделал неправильно?

О. Типичным символом разделителя аргументов является пробел, однако допускается также использование других символов для разделения аргументов (таких, как запятая или точка с запятой). Поэтому для того, чтобы использовать в качестве аргумента строку ADsPath, нужно заключать ее в двойные кавычки, тогда сценарий не будет интерпретировать запятые как разделители. В некоторых случаях после того, как аргумент передан внутрь сценария, может потребоваться удалить символы двойных кавычек. Для этого можно использовать подстановку, что показано в примере листинга 5. Данный код представляет собой весьма удобный способ удаления или замены символов и может использоваться для организации фильтрации двойных кавычек. Базовый синтаксис выглядит следующим образом: %PATH:str1=str2%. Более подробные сведения о подстановках переменных можно получить, набрав в командной строке команду SET /?.

Если вы запустили команду CALL /?, как описывалось выше, то наверняка обнаружили еще один метод удаления двойных кавычек. В листинге 6 показан пример использования команды CALL для фильтрации двойных кавычек.

Запомните, что если строка аргумента содержит пробелы или еще какие-либо символы, которые могут трактоваться как разделители, то для того, чтобы сценарий воспринимал строку как единый аргумент, она должна заключаться в двойные кавычки. Типичным примером входных данных сценария, в которых могут содержаться пробелы, являются описания путей к входным и выходным файлам, а также к файлам журналов. Кроме того, желательно заключать в кавычки адреса электронной почты, разделенные запятыми или точкой с запятой.

В. Имеется сценарий, у которого есть три аргумента. Могу ли я присвоить аргументам метки таким образом, чтобы можно было указывать их в любом порядке, а потом проверить, что все три аргумента переданы сценарию и ничего не потерялось?

О. Да, можно создать такой сценарий, у которого есть три аргумента, для которых используются метки. В качестве примера я разработал второй вариант сценария для запуска Robocopy, который называется AdvancedArguments ForRobo.bat, приведенный в листинге 7. Здесь используется набор из трех стандартных аргументов, которым далее присваиваются метки. В результате параметры размещения исходного, целевого файла, а также файла журнала могут указываться в произвольном порядке. Синтаксис запуска сценария выглядит следующим образом:

AdvancedArgumentsForRobo.bat 
/S:"D:sourcelocation"
/D:"serverdestinationlocation"
/L:"D:logfileslog.txt".

Здесь /S определяет местонахождение исходного файла (source), /D задает местонахождение целевого (destination) файла, а /L соответствует месту размещения файла журнала (log) работы программы Robocopy. Обратите внимание, что можно задавать как локальные, так и доступные сетевые каталоги.

При работе с аргументами я рекомендую руководствоваться приведенными ниже основными принципами, которым я следовал при создании сценария AdvancedArgumentsForRobo.bat.

  • Если пользователь попытается запустить сценарий без аргументов, необходимо вывести экран справки, содержащий подсказки для корректного ввода аргументов.
  • По возможности выполняйте проверку правильности ввода аргументов. Например, в сценарии, показанном в листинге 7, для проверки существования каталогов источника и пункта назначения используется оператор IF EXIST. Кроме того, если вы работаете с аргументами, имеющими метки, желательно проверять, не задан ли какой-либо из них дважды и не пропущен ли какой-либо из аргументов. Как реализовать подобную проверку, показано во фрагменте кода с меткой A в листинге 7.
  • Предоставьте пользователю возможность принять окончательное решение перед запуском процедур. Эта возможность особенно важна в тех случаях, когда в сценарии выполняются операции, связанные с изменением, копированием или удалением файлов, учетных записей пользователей, членов групп и т. д. Если сценарий задействует только функции чтения или выполняет те или иные запросы, то наличие данной возможности не столь принципиально, однако я все равно советую реализовывать ее. В тех случаях когда предполагается использовать сценарий для запуска тех или иных операций по расписанию, будет целесообразно игнорировать или исключить из него код, требующий ввода данных пользователем.

В. Можно ли использовать аргументы при работе с ярлыками и в планировщике заданий?

О. Аргументы можно задавать в ярлыках и указателях планировщика заданий, однако я рекомендую добавлять аргументы по завершении процесса создания ярлыка или работы мастера создания задачи Task Setup Wizard. В ходе работы мастера создайте указатель на .bat файл, а затем добавьте аргументы вручную. Если описание пути к сценарию содержит пробелы, не забудьте заключить его — но не аргументы сценария! — в двойные кавычки. Если при создании ярлыков используется утилита shortcut.exe (средство для создания ярлыков Microsoft), то в этом случае для задания аргументов можно использовать ключ -a данной утилиты.

В. Можете ли Вы порекомендовать какой-либо быстрый способ использования аргументов командной строки без необходимости ввода аргументов с клавиатуры для исключения возможных ошибок ввода?

О. Для того чтобы сделать ввод команд более точным, я пользуюсь несколькими приемами. Прежде всего, в диалоговом окне свойств Properties командной строки нужно выбрать режимы быстрого редактирования QuickEdit Mode и вставки Insert Mode. Это позволит копировать текст из окна командной строки, а также вставлять его туда. Первое, что вводится в командной строке, — это путь к сценарию. Следует понимать, что длинный путь к сценарию создаст массу дополнительных хлопот. Одна маленькая опечатка может привести к появлению ошибок.

На мой взгляд, самым простым способом быстрого поиска пути к сценарию является использование свободно распространяемой утилиты SAMenu от Smaller Animals Software. Это небольшое расширение проводника Windows дает возможность копировать путь к файлу в буфер обмена путем выбора соответствующего пункта из контекстного меню, вызываемого правой кнопкой мыши. Для этого нужно просто щелкнуть правой кнопкой на файле сценария и выбрать пункт Copy Path to Clipboard. Далее щелчком правой кнопкой мыши в окне командной строки можно перенести скопированное значение пути к сценарию в командную строку. Аналогичным образом можно вводить в командную строку пути к другим файлам и каталогам. Также можно использовать перетаскивание необходимых файлов в окно командной строки: следует просто выбрать свой сценарий и перетащить его мышью в окно командной строки, нажав на левую или правую кнопку.

Как мы видели, данные можно копировать в окно командной строки, однако при этом следует соблюдать осторожность. Допустим, вы хотите скопировать в окно командной строки путь к файлу и набор аргументов, которые берете, скажем, из текстового файла, а эти данные содержат символ возврата каретки. Тогда при вставке этих данных в командную строку сценарий будет запущен на выполнение немедленно.

Используйте аргументы

Возможность передачи входных данных — это ключ к созданию весьма эффективных сценариев и упрощению их использования. Использование аргументов для работы с входными данными — надежное, проверенное временем решение. Вы можете убедиться в этом, загрузив прилагающийся к данной статье код и протестировав эти сценарии в своей инфраструктуре. Они предоставят несколько новых методик, которые пополнят ваш арсенал приемов разработки сценариев.

Дик Льюис (dlewis@winnetmag.com) — Старший системный инженер компании CKT Consulting в Калифорнии. Имеет сертификаты MCSE и MCT, специализируется на системах управления масштаба предприятия.


Возможные способы ввода данных

Использование аргументов в командной строке традиционно считается оптимальным вариантом для реализации ввода внешних данных в сценарии. Но существуют и альтернативные способы.

Например, в Windows NT и последующих версиях с помощью команды For /F можно выполнять построчное считывание данных из входного файла. В тех случаях когда вводимые внешние данные имеют большой объем — скажем, список из 200 компьютеров или 500 пользователей, — обработка входного файла может оказаться предпочтительным решением. При этом можно разработать сценарий, в котором аргументы будут использоваться для передачи информации о размещении входного и выходного файлов; таким образом, применение технологии обработки файлов не исключает возможности использования аргументов.

Еще один вариант ввода данных — с помощью меню. Если потенциальные пользователи сценария не имеют опыта работы с этим инструментом, можно предложить им статическое меню с приглашением для ввода текста. Наилучшими альтернативами в этом случае являются команда Choice из пакета Microsoft Windows Resource Kit, а также команда Set /P из операционной системы Windows.


Методы работы с аргументами

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

  • Располагайте аргументы по порядку. Порядок следования аргументов указывает на то, что представляет собой каждый из них. Многие утилиты из пакетов Resource Kit, а также программы от независимых производителей принимают входные данные через аргументы, упорядоченные определенным образом. Примером данного подхода может служить сценарий копирования файлов из одного места в другое, использующий утилиту Robocopy. Здесь логический порядок следования аргументов будет таким: размещение исходного файла, размещение целевого файла, размещение файла журнала. Если в данном случае поменять местами источник и пункт назначения, то файлы из пункта назначения будут переписаны поверх исходных файлов.
  • При работе с аргументами используйте метки. Например, можно задать метки таким образом, чтобы сценарий понимал, что аргументу, перед которым стоит метка /S, соответствует файл-источник, а аргумент, указанный после метки /D, - это пункт назначения. Использование маркированных аргументов исключит возможность появления последовательных ошибок в упомянутом выше примере с запуском утилиты Robocopy. Но если вы решили использовать этот подход, то в вашем сценарии должна быть предусмотрена процедура предварительного перехвата аргументов и удаления из них информации о метках. Пример его реализации показан в листинге 7.
  • В некоторых сценариях все аргументы могут быть просто элементами списка однотипных объектов, передаваемых сценарию. Примером может служить сценарий Ping, который запускает утилиту ping для каждого из серверов, чьи имена были переданы ему в качестве аргументов. Если вы собираетесь использовать данный подход, то необходимо организовать внутри сценария некоторый цикл, который бы последовательно брал каждый из имеющихся аргументов и запускал для него соответствующую процедуру. Пример реализации такой процедуры в сценарии был показан в листинге 4, где с помощью утилиты ping опрашивался список серверов, имена которых были переданы сценарию в виде аргументов.

Листинг 1. RoboArg.bat

If “%2”==”” Echo Недостаточное количество аргументов & goto :EOF 
If %3 GTR 1 Echo Слишком много аргументов & goto :EOF
Robocopy %1 %2 /E /PURGE /SEC /NP /R:1 /W:1

Листинг 2. TestVar.bat

BEGIN COMMENT 
:: Для запуска сценария используйте команду
:: TestVar.bat переменная1 переменная2 переменная3.
END COMMENT
Echo Путь к сценарию: %0
Echo Первая переменная: %1
Echo Вторая переменная: %2
Echo Третья переменая: %3

Листинг 3. Test0Var.bat

BEGIN COMMENT 
:: Для запуска сценария используйте команду
:: Test0Var.bat.
END COMMENT
Call :GetPath %0
Goto :EOF

:GetPath
Echo.
BEGIN COMMENT
:: Расширяем %0 буквой диска и путем
END COMMENT
Echo Путь: %∼dp1
BEGIN COMMENT
:: Создание выходного файла по указанному пути.
END COMMENT
Set OutFile=%∼dp1outputfile.txt
Dir /AD /B > %OutFile%
Goto :EOF

Листинг 4. TestLotsOfArgs.bat

BEGIN COMMENT 
:: Для запуска сценария используйте следующую команду,
:: в которой укажите несколько имен своих серверов:
:: TestLotsOfArgs.bat Server1 Server2 Server3 Server4
:: Server5 Server6 Server7 Server8 Server9 Server10
:: Server11 Server12
END COMMENT
@Echo Off
Setlocal
Set counter=0
If '%1'=='' Echo Не заданы аргументы servername & Goto :last
Set /A counter+=1
Echo ARG %counter%) %1
Ping -n 1 %1
Set ARGStr=%1

:TOP

If '%2'=='' Goto :last
Set /A counter+=1
Echo ARG %counter%) %2
Ping -n 1 %2
Set ARGStr=%ARGStr% %2
Shift /1
Goto :TOP

:last

Echo Здесь приведена вновь собранная строка аргументов: %ARGStr%
Endlocal
Goto :EOF

Листинг 5. Фильтрация двойных кавычек

:: Call the script MyScriptWoQuotes.bat. 
"ou=server,dc=sales,dc=mycompany,dc=com"
Set ADsPath=%1
Echo Аргумент, содержащий кавычки: %ADsPath%
Set ADsPath=%ADsPath:"=%
Echo Аргумент без кавычек: %ADsPath%

Листинг 6. Фильтрация двойных кавычек с помощью команды Call

@Echo Off 
Set ADSpath="ou=server,dc=sales,dc=mycompany,dc=com"
Echo Аргумент, содержащий кавычки: %ADSpath%
Call :remquotes %ADSpath%
Goto :EOF

:remquotes
Set ADsPath=%∼1
Echo Аргумент без кавычек: %ADsPath%
Goto :EOF

Таблица. Варианты использования параметров командных файлов

ПараметрФункция
%∼f1Заменяет %1 на полное описание пути (fully qualified pathname)
%∼d1Заменяет %1 на буквенное обозначение диска (только)
%∼p1Заменяет %1 на описание пути (только)
%∼n1Заменяет %1 на имя файла (только)
%∼x1Заменяет %1 на расширение файла (только)
%∼a1Заменяет %1 на атрибуты файла
%∼t1Заменяет %1 на время/дату создания файла
%∼z1Заменяет %1 на размер файла