Пакетные файлы. Консоль живее всех окон. Часть 1

Пакетные файлы. Консоль живее всех окон. Часть 1

Здравствуйте, уважаемые любители сами знаете чего:-). Повстречал я недавно такую ситуацию. Одному из штатных "программистов" понадобилось переустановить Windows. Предыдущую инсталляцию он успешно "снес", загрузился с загрузочной дискеты, а вот поиски заветного инсталляционного файла заняли у него довольно продолжительное время. А знаете почему? Потому, что инсталляционный пакет лежал у него на винчестере. Кстати, рекомендую копировать Win-dows сначала на винчестер из-под какой-нибудь ДОСовской оболочки типа Norton Commander или предыдущей версии Windows, а затем запускать установку с загрузочной дискеты — так процесс осуществляется ощутимо быстрее.

Поиски заветного запускаемого файла в командной строке также представляли для моего знакомого довольно нетривиальную задачу: список файлов забегал за границу экрана:-). Поэтому сегодня мы поговорим о командных файлах в Windows. Тема стара и заезжена, но, тем не менее, весьма, по моему мнению, полезная. Я постараюсь также коснуться тех новых возможностей, которые преподнесла нам консоль в WinXP (в следующей части, правда:-).

Не будем повторять прописные истины (читай использование dir и т.д.), а начнем с более вкусного. Итак, пишем наш первый (или не первый) командный файл. Что это вообще такое? Это обыкновенный текстовый файл с расширением .bat или .cmd, .vbs, .js, в котором последовательно записаны консольные команды. Каждая строка — это команда. В простых случаях все именно так и выглядит. Но командный процессор позволяет несколько большую свободу действий, нежели просто последовательное выполнение команд. Также можно использовать сервер сценариев Windows, CScript.exe для выполнения в командной оболочке сложных сценариев. Сервер сценариев Windows поддерживает скрипты, написанные в редакторах VBScript и Jscript. Но об этом как-нибудь в другой раз. Перечислим основные команды, используемые в "простых" *.bat-скриптах, не обращающихся ни к VBS, ни к JS: Call, Echo, Endlocal, For, Goto, If, Pause, Rem, Setlocal, Shift.

Это т.н. служебные команды. Особо останавливаться на отличиях командной оболочки "Окошек" серии 95 от NT-серии я не буду, т.к. уже кто не ленился (а вы ведь не ленивы?), тот уже давно перешел с Windows 9x на более стабильные и совершенные ОС. Будем думать, у вас уже стоит хотя бы Win2000. Предчувствую кучу тухлых помидоров в мою сторону: мол, 98 и легче, и быстрее, но… Но этот спор не является темой данной статьи. Так что мы подумали, и я решил:-). У кого слабые машины, ставьте "Линукс", который и стабильнее и быстрее 98-х, а в гульки вы ведь на слабой машине все равно не играете — так ведь? А остального софта под *nix теперь полно. Командная оболочка — это cmd.exe (Пуск -> Выполнить -> cmd.exe). Кстати, можно несколько настроить окно консоли, щелкнув правой кнопкой по заголовку и зайдя в свойства. Там можно установить цвет, шрифт, размер окна (он указывается в символах!) и другое. Настоятельно рекомендую поставить галочки напротив "Быстрой вставки" и "Выделения мышью". Это позволит копировать и вставлять текст из консоли правой кнопкой мыши. И еще один совет. В Total Commander'е есть полезная "фича": идем в Команды -> Запустить Сеанс Dos. И вам откроется консоль с рабочим каталогом, в котором в данный момент находится курсор, т.е. папка активной панели. Итак, открываем наш любимый Блокнот (вы еще не нашли себе подходящего заменителя? Тогда быстрее в Инет — там таких полно!). И ваяем первую консольную программу. Конечно, ее возможности далеко уступают возможностям консольных интерпретаторов в *nix-системах, но все же. Итак, первое. Командные файлы могут получать параметры, переданные им из командной строки.

Например:
shell> myCmd.bat parametr_1 parametr_2

Возможна передача до десяти параметров. В самом .bat-файле это обрабатывается следующим образом: net send %1 %2. Если теперь эту строку сохранить в файле bat.bat и запустить его из консоли командой shell> bat.bat hostname Hello World!, то результатом будет выполнение команды net send hostname HelloWorld!. Если вам вдруг станет мало десяти переменных (0-9), можно использовать команду shift, которая выполняет сдвиг значений переменных в предшествующую (т.е. из %1 в %0 и т.д.). Обратного сдвига не существует. Возможен сдвиг с параметром shell> shift /3. Эта команда начнет сдвиг с %4 (%4-> %3).
Итак, каким образом в командный файл можно передавать параметры? Что еще жизненно необходимо? Выводить информацию, организовывать циклы, управлять работой программы.

Условия. Организуется при помощи if. Синтаксис довольно прост:

if [not] строка1==строка2 команда [else выражение]
или, если разрешены расширения команд:
if [/i] строка1 оператор_сравнения строка2 команда [else выражение]
где оператор_сравнения может принимать следующие значения:
EQU — равно
NEQ — не равно
LSS — меньше
LEQ — меньше или равно
GTR — больше
GEQ — больше или равно
Все остальные варианты синтаксиса можно "спросить" у справочной системы.

Сразу рассмотрим пример. В зависимости от введенных параметров будем отвечать пользователю.
@echo off
IF %1==Hello (echo privet) ELSE echo "Hello World"

Здесь есть один нюанс. Первая строка выключает вывод команд на экран пользователю. Конструкция If …Else должна находиться в одной строке, и если команда, которая выполняется при выполнении условия должна заканчиваться концом строки, команду следует заключать в круглые скобки.
Управлять работой программы можно при помощи конструкции goto. (Так люто ненавидимой всеми учебниками, особенно по С\С++:-)). Но в данном случае вы вряд ли без нее обойдетесь. Синтаксис таков:
goto метка
Метка задается при помощи такого вот синтаксиса:
:метка

В следующем примере в зависимости от введенных параметров при помощи меток будет организовано то же приветствие, что и в предыдущем случае:
@echo off
IF %1==Hello (goto metka_1) ELSE goto metka_2
:metka_1
echo privet
goto end
:metka_2
echo "Hello World"
:end

Здесь выход из файла организован при помощи заведения специальной метки. При включенных расширениях выход может быть реализован так (я не говорил, что расширения по умолчанию включены?):
goto :EOF

Когда используется команда goto с меткой :EOF, перед меткой должно быть вставлено двоеточие. Управление будет передано в конец файла текущего пакетного сценария для выхода из него без назначения метки. Ограничение на имена меток таковы. Системой используется только 8 первых символов меток и может содержать пробелы, но не может содержать разделители (точка с запятой, например). Если командным процессором заданная goto-метка не будет найдена, выполнение скрипта будет остановлено.

Циклы организуются при помощи следующего синтаксиса:
for {%переменная|%%переменная} in (множество) do команда [ПараметрыКоманднойСтроки]
Пожалуй, наиболее часто используемая и популярная команда с весьма "завернутым" синтаксисом для начинающих. Посему посвятим ей несколько больше времени.
%%переменная — задает управляющую переменную. Регистр в именах учитывается.
(множество) — задает то множество, значения из которого может принимать переменная, описанная в предыдущем параметре.
Ну, и команда [ПараметрыКоманднойСтроки] — собственно то, что будет выполняться циклически. Все эти параметры являются обязательными. For может вызываться как из командной строки (т.е. набираться ручками), так и из командного файла. При вызове из командного файла переменную следует задавать в виде %%name, а при вызове из консоли — %name. Имена переменных учитывают регистр. Параметр множество может представлять собой множество имен файлов (*.doc *.txt *.me). Маска задания файлов стандартная.

Пример:
@echo off
for %%f in (*.bat) do type %%f
При выполнении этого скрипта на экран будет выведено содержание всех .bat-файлов в данной директории. При использовании расширений возможно использование дополнительных форм команды for.
For может работать только с каталогами (т.е. параметр множество будет представлять собой набор имен каталогов). Имена могут содержать подстановочные знаки (*,?). Синтаксис таков:
for /D {%% | %}переменная in (множество) do команда [ПараметрыКоманднойСтроки]

Пример:
@echo off
for /D %%f in (*) do echo %%f

При выполнении данного скрипта на экран будет выведен список всех вложенных директорий.
For может рекурсивно работать с деревом каталогов. Синтаксис таков:

for /R [[диск :]путь] {%% | %}переменная in (множество) do команда [ПараметрыКоманднойСтроки]

For выполняется для каждого вложенного каталога. Это полезно, если, например, вам необходимо выполнить какие-либо действия для ВСЕХ папок. For начинает работу с каталога, заданного параметром [[диск :]путь. Если каталог не задан, то используется текущий. Если параметр множество задан "." (точка), то просто перечисляются каталоги.

Пример:
@echo off
for /R c:\windows %%f in (w*) do echo %%f
При запуске этого на выполнение на экран будет выведен список всех файлов в каталоге c:\windows, начинающихся с символа "w".
Также можно задавать и "обычные" циклы, т.е. с параметром, принимающим последовательные значения из заданного диапазона с заданным шагом.

Делается это при помощи следующего синтаксиса:
for /L {%% | %}переменная in (НачальноеЗначение#,шаг#,КонечноеЗначение#) do команда [ПараметрыКоманднойСтроки]
В общем, кто работал с "нормальными" языками программирования, поймет, как использовать данную "фичу". Но все же приведу пример:
@echo off
for /L %%f in (0#,1#,10#) do echo This step # %%f

Результатом его работы является вывод 11 сообщений с включением номера итерации.

А теперь переходим к самой интересной способности For — разбору файлов. Это наиболее типичная задача для batch-файлов. Однако стоит оговорится, что под понятием "файл" выступать может и какая-либо команда еще (если кто не знает: консоль — это тоже своеобразный файл). Это дает возможность "скармливать" for информацию, которую выдает какая-либо другая команда. Но обо всем по порядку.

Разбор файлов имеет следующий синтаксис:
for /F ["КлючевыеСловаРазбора"] {%% | %}переменная in (МножествоИменФайлов) do команда [ПараметрыКоманднойСтроки]
Множество имен файлов задается стандартно. Разбираются все файлы по порядку. Вместо ключевых слов разбора могут использоваться следующие параметры:
eol=c — задание символа конца строки.
skip=n — пропуск энного количества строк с начала файла.
delims=xxx — задание разделителя в строке (стандартный разделитель — пробел и символ табуляции).
tokens=x,y,m-n — задание переменных, в которые будут заносится строки. Возможно указание через запятую или тире (-). Если последний символ (*), то создается еще одна переменная, в которую помещается остаток строки.
При использовании вышерассмотренных параметров необходимо применять следующий вид записи:
for /F ["usebackqКлючевыеСловаРазбора"] {%% | %}переменная in ("МножествоИменФайлов") do команда [ПараметрыКоманднойСтроки]

Например:
@echo off
for /F "usebackq tokens=1,2*" %%i in (txt.txt) do (echo " %%i -> %%j" )
Результатом будет вывод первых двух слов каждой строки из файла txt.txt.
for /F ["usebackqКлючевыеСловаРазбора"] {%% | %}переменная in ('СимвольнаяСтрока') do команда [ПараметрыКоманднойСтроки]

Например:
@echo off
for /F "usebackq tokens=1,2*" %%i in ('XXXX Windows, use Linux!') do (echo "%%i -> %%j" )
Результат — вывод первых двух слов из фразы, заключенной в одинарные ('') кавычки со скобками.
for /F ["usebackqКлючевыеСловаРазбора"] {%% | %}переменная in ('команда') do команда [ПараметрыКоманднойСтроки]"

Например:
@echo off
for /F "usebackq skip=4" %%i IN ('net session') DO echo %%i
Результат — список компьютеров, подключенных к вашему.
Стоит упомянуть, что переменные также могут иметь модификаторы, которые расширяют их возможности. Список модификаторов также можно найти в справке Windows. Модификаторы позволяют заменять переменные полным путем к файлу, осуществлять поиск ограниченной системной переменной PATH, а также многое другое.

Call. Это вызов другого пакетного файла из исполняющегося в данный момент. Синтаксис такой же, как и из консоли (т.е. сохраняется возможность передачи в него входных параметров). Возможен вызов (переход) по метке.

Синтаксис следующий:
call [[диск:][путь] имя_файла [пакетные_параметры]] [:метка [аргументы]]
setlocal (endlocal) — используется для установления переменных среды в пакетном файле и соответственно для восстановления их предыдущих значений. Обычно используется для того, чтобы в пакетном файле не использовать полные абсолютные пути для файлов и папок. Просмотреть текущее значение системных переменных можно при помощи команды set. С ее же помощью можно создавать и новые системные переменные. Например, вот так:
set photo_=c:\my_photo

После этого данную переменную можно использовать в своих командных файлах таким вот образом (используются также стандартные системные переменные):
dir %photo_%

При выполнении данной команды строка %photo_% будет заменена на my_photo.
Перенаправление ввода-вывода. Согласитесь, не всегда результаты работы вашего супер-пупер-навороченного скрипта удобно лицезреть в консоли. Желательно вывести все это "счастье" в какой-нибудь файл. А если скрипт должен получать кучу параметров, которые и запомнить-то тяжело? Для этого и служат операторы перенаправления ввода-вывода. Возможны следующие операторы:
> — вывод результатов выполнения команды в файл;
< — чтение входных данных с клавиатуры;
> > — дописывает данные в существующий файл без удаления уже существующих там записей;
> & — считывает данные на выходе одного дескриптора как входные данные для другого дескриптора.
<& — считывает входные данные одного дескриптора как выходные данные другого дескриптора.
| — считывает выходные данные одной команды и записывает их на вход другой команды. Эта процедура известна под названием "канал".

Доступны следующие дескрипторы ("ссылки", что ли, их назвать — это для тех, у кого "умные" слова вызывают неприятные судороги:-):
STDIN (0) — стандартный ввод с клавиатуры;
STDOUT (1) — стандартный вывод;
STDERR (2) — стандартный вывод для ошибок;
UNDEFINED (3-9) — определяются для каждой прикладной программы отдельно.

В скобках даны числовые эквиваленты дескрипторов. Применение операторов, думаю, понятно (что-то типа "dir > dir_file.txt"). Оператор канал (|) позволяет выход одной команды отправить на вход другой. Обычно применяется с тремя командами-фильтрами:
More — постраничный вывод результатов. Применяется в случае, если при выполнении программы текст не умещается на экране;
Find "строка" — поиск во входном потоке. Позволяет выводить только строки, в которых будут найдены символы, указанные в параметрах;
Sort — сортировка. Позволяет сортировать входной поток (им может быть и какой-либо файл). Сортировка возможна и при вводе с клавиатуры: введите команду без параметров, а сортируемые строки — через ENTER. Когда ввод будет закончен, нажмите CTRL+Z и ENTER. Введенный текст будет выведен в отсортированном виде.

Все команды имеют много ключей использования. Все их приводить не имеет смысла. Эту информацию можно получить прямо в консоли, введя "команда /?", или в справочной системе Windows.
Предвидя множество вопросов по практическому использованию всего вышеизложенного, хочу в конце привести парочку полезных скриптов. Первый из них пригодится вам в том случае, если вы хотите закрыть все файлы, открытые клиентами на вашем компьютере. Сделать это можно из консоли, введя

for /F "skip=2 tokens=1" %i in ('net file') do net file %i /close"

или, из *.bat-файла,
for /F "skip=2 tokens=1" %%i in ('net file') do net file %%i /close.

А сейчас представьте себе такую ситуацию. У вас есть таблица (Word, Excel), которую вам нужно занести в базу данных MySql, причем специализированного софта для этого нет под рукой (а таковой в природе существует). Тогда сохраняем из Excel'a таблицу как "текстовые файлы (с разделителями табуляции)", а в Блокноте ваяем вот такой вот небольшой скриптик:

@echo off
for /F "usebackq tokens=1,2,3" %%i in (%1) do (echo " insert into table_name (name_1,name_2,name_3) values (%%i %%j %%k) " )

Терперь, выполнив shell> mybat excel.txt > cript.txt, получим заготовку для создания таблицы. После просто скопируете содержимое файла cript.txt в ответ на приглашение клиента mysql.exe. И система все сделает за вас!

Для тех, кто ленится. Если вам неохота набирать имя исполняемого файла ручками, а при двойном клике на нем консоль открывается, команды выполняются, а затем окошко закрывается, и вы ничего не успеваете прочесть:-), допишите в конце такую вот команду: pause 0. Это приостановит выполнение файла до нажатия на клавишу.
Ну вот, пожалуй, и все на сегодня. Основы я вам рассказал, значение и применение конкретных ключей к командам можно узнать прямо в консоли, дальше — только ваша работа!

Продолжение следует.

Спичеков Александр aka MentALzavR, zavr6@mail.ru



Компьютерная газета. Статья была опубликована в номере 21 за 2004 год в рубрике soft :: ос

©1997-2021 Компьютерная газета