Использование bat файлов для создания «Заданий по расписанию». Bat программирование


Взаимодействие между несколькими .bat, мультиплеер на .bat / Хабр

Бат-файлы лишены возможности передавать по сети какую-нибудь полезную информацию друг другу. Нет сокетов, ну и ладно, зато есть простая работа с именованными областями данных, т.е. файлами. Создание и чтение однострочных текстовых файлов вообще упрощено до предела. Достаточно выполнить echo Text>file.txt и file.txt будет содержать строку «Text». Прочитать строку из файла можно так: set /p var= Итак, можно передавать информацию между батниками через файлы. А если эти файлы будут находиться на расшаренных сетевых ресурсах, то между собой вполне могут общаться батники, запущенные на различных компьютерах.

Вот небольшой пример клиент-серверного приложения, такого себе rexec для бедных.

файл rexec_server.bat:

set checkFolder=\\IMP5\PUBLIC_RW :loop @ping -n 2 127.0.0.1 > nul @if not exist "%checkFolder%\!cmd" goto loop @call "%checkFolder%\!command.bat" > "%checkFolder%\!result" @del "%checkFolder%\!cmd" @goto loop

файл rexec_client.bat:

@echo off set checkFolder=\\IMP5\PUBLIC_RW :mainloop set /p c=^> if "%c%"=="exit" exit if "%c%"=="quit" exit echo %c%>"%checkFolder%\!command.bat" echo.>"%checkFolder%\!cmd" :waitloop ping -n 2 127.0.0.1 > nul if exist "%checkFolder%\!cmd" goto waitloop type "%checkFolder%\!result" del "%checkFolder%\!result" goto mainloop

Вот пример работы:

Делает оно следующее: rexec_server.bat ждёт от клиента командную строку и выполняет её на том компьютере, на котором он запущен. С клиентом он общается через расшаренную папку «\\IMP5\PUBLIC_RW» (разумеется, вам нужно будет заменить её на свою, если захотите поэкспериментировать). Чтобы клиент и сервер не пытались раньше времени прочитать файлы, которые сейчас для них пишутся, были предусмотрены файлы-флаги, которые служат только для того, чтобы обозначить, что информация уже сохранена полностью.

Ну и на закуску — мультиплеерная игра на .bat «крестики-нолики, три в ряд». Здесь для сохранения целостности данных реализован механизм критических секций для блокирования попыток одновременного обращения к файлам. Помните, что перед запуском нужно в строке «set FLAG_DIR=\\IMP5\SHARED_RW» указать свою расшаренную папку (кстати, через одну папку могут играться сразу несколько игр).

Файл xo.bat:

@echo off cls set FLAG_DIR=\\IMP5\SHARED_RW call :create_chars :restart echo Please wait... call :sys_utils init "%0" set cmdPrefix=$p%__PID% rem ------- connecting -------- call :sys_utils enter_critical_section cls call :sys_utils fetch_flag ready_to_play if "%RESULT%"=="" ( call :sys_utils set_flag ready_to_play %cmdPrefix% set symbol=X set symbol2=O set server=1 ) else ( set cmdPrefix=%RESULT% call :sys_utils set_flag %RESULT%_client_ready --- set symbol=O set symbol2=X set server=0 ) call :sys_utils leave_critical_section if "%server%"=="0" goto client1 call :wait_for_client call :sys_utils set_flag %cmdPrefix%_server_ready_too --- goto skipClient1 :client1 call :wait_for_server if "%serverFailure%"=="1" goto restart :skipClient1 rem ------- connected -------- call :clear_field if "%server%"=="1" (set curMode=your_turn) else (set curMode=enemy_turn) :main_game_loop cls call :check_win call :render_field if "%winSymbol%"=="%symbol%" goto you_win if "%winSymbol%"=="%symbol2%" goto enemy_win if not "%curMode%"=="your_turn" goto skipTurn1 echo. echo Your are "%symbol%" echo. set /p tmp=Please enter <nul if "%f1%"=="1" set /p tmp=1, <nul if "%f2%"=="2" set /p tmp=2, <nul if "%f3%"=="3" set /p tmp=3, <nul if "%f4%"=="4" set /p tmp=4, <nul if "%f5%"=="5" set /p tmp=5, <nul if "%f6%"=="6" set /p tmp=6, <nul if "%f7%"=="7" set /p tmp=7, <nul if "%f8%"=="8" set /p tmp=8, <nul if "%f9%"=="9" set /p tmp=9, <nul echo or 'q' for quit echo. set /p "tmp=Your turn: " if "%tmp%"=="q" goto quit_game if "%tmp%"=="Q" goto quit_game call set varName=%%f%tmp%%% if not "%varName%"=="%tmp%" goto main_game_loop call set f%tmp%=%symbol% call :sys_utils set_flag %cmdPrefix%_%symbol%_move f%tmp% set curMode=enemy_turn goto main_game_loop :skipTurn1 if not "%curMode%"=="enemy_turn" goto skipTurn2 echo. echo Waiting for another player :wait_for_player0 set /p tmp=.<nul ping -n 2 127.0.0.1 > nul call :sys_utils fetch_flag %cmdPrefix%_%symbol2%_move if "%RESULT%"=="" goto wait_for_player0 echo %RESULT% if "%RESULT%"=="q" goto other_player_quit call set %RESULT%=%symbol2% set curMode=your_turn goto main_game_loop :skipTurn2 goto main_game_loop :quit_game call :sys_utils set_flag %cmdPrefix%_%symbol%_move q exit :other_player_quit cls echo Other player has left the game. echo Press 'Enter' to search for another one. pause > nul goto restart :you_win echo. echo You Win echo. echo Press 'Enter' pause > nul goto restart :enemy_win echo. echo You Lose echo. echo Press 'Enter' pause > nul goto restart :wait_for_client echo Waiting for client :wait_for_client1 set /p tmp=.<nul ping -n 2 127.0.0.1 > nul call :sys_utils fetch_flag %cmdPrefix%_client_ready if "%RESULT%"=="" goto wait_for_client1 exit /b :wait_for_server echo Waiting for server set serverFailure=0 set /a waitCnt=4 :wait_for_server1 set /a waitCnt-=1 if "%waitCnt%"=="0" ( set serverFailure=1 exit /b ) set /p tmp=.<nul ping -n 2 127.0.0.1 > nul call :sys_utils fetch_flag %cmdPrefix%_server_ready_too if "%RESULT%"=="" goto wait_for_server1 exit /b :clear_field set "f1=1" set "f2=2" set "f3=3" set "f4=4" set "f5=5" set "f6=6" set "f7=7" set "f8=8" set "f9=9" exit /b :create_chars set "charX0= # # ^|" set "charX1= # # ^|" set "charX2= # ^|" set "charX3= # # ^|" set "charX4= # # ^|" set "charX5=-------+" set "charO0= ### ^|" set "charO1= # # ^|" set "charO2= # # ^|" set "charO3= # # ^|" set "charO4= ### ^|" set "charO5=-------+" set "charXW0=.#...#.^|" set "charXW1=..#.#..^|" set "charXW2=...#...^|" set "charXW3=..#.#..^|" set "charXW4=.#...#.^|" set "charXW5=-------+" set "charOW0=..###..^|" set "charOW1=.#...#.^|" set "charOW2=.#...#.^|" set "charOW3=.#...#.^|" set "charOW4=..###..^|" set "charOW5=-------+" for %%i in (1,2,3,4,5,6,7,8,9) do call :create_empty_char %%i exit /b :create_empty_char set "char%10= ^|" set "char%11= ^|" set "char%12= %1 ^|" set "char%13= ^|" set "char%14= ^|" set "char%15=-------+" exit /b :check_win set winSymbol=. call :check3 1 2 3 call :check3 4 5 6 call :check3 7 8 9 call :check3 1 4 7 call :check3 2 5 8 call :check3 3 6 9 call :check3 1 5 9 call :check3 3 5 7 exit /b :check3 call set tmp1=%%f%1%%%%f%2%%%%f%3%% call set tmp2=%%f%1%%%%f%1%%%%f%1%% if "%tmp1%"=="%tmp2%" ( call set "winSymbol=%%f%1%%" call set "f%1=%%f%1%%W" call set "f%2=%%f%2%%W" call set "f%3=%%f%3%%W" ) exit /b :render_field call :render_line %f1% %f2% %f3% call :render_line %f4% %f5% %f6% call :render_line %f7% %f8% %f9% exit /b :render_line call echo %%char%10%%%%char%20%%%%char%30%% call echo %%char%11%%%%char%21%%%%char%31%% call echo %%char%12%%%%char%22%%%%char%32%% call echo %%char%13%%%%char%23%%%%char%33%% call echo %%char%14%%%%char%24%%%%char%34%% call echo %%char%15%%%%char%25%%%%char%35%% exit /b rem ----------------- atom -------------- :sys_utils goto %1 exit /b :init if "%FLAG_DIR%"=="" set FLAG_DIR=. set UNIQ_BAT_ID=%COMPUTERNAME%_%USERNAME%_%~n2 set /A CRITICAL_SECTION_LEVEL=0 call :enter_critical_section call :test_flag --null-- $pid$ set /A __PID=%RESULT% if [%__PID%]==[0] set /A __PID=10000000 if [%__PID%]==[] set /A __PID=10000000 if [%__PID%]==[99999999] set /A __PID=10000000 set /A __PID=__PID+1 call :set_flag --null-- $pid$ %__PID% call :leave_critical_section set UNIQ_BAT_ID=%UNIQ_BAT_ID%_pid%__PID% exit /b :set_flag call :enter_critical_section echo %3>"%FLAG_DIR%\%2" call :leave_critical_section exit /b :remove_flag call :enter_critical_section if exist "%FLAG_DIR%\%2" del "%FLAG_DIR%\%2" call :leave_critical_section exit /b :fetch_flag call :enter_critical_section set "RESULT=" if exist "%FLAG_DIR%\%2" ( set /p RESULT=<"%FLAG_DIR%\%2" del "%FLAG_DIR%\%2" ) call :leave_critical_section exit /b :test_flag call :enter_critical_section set "RESULT=" if exist "%FLAG_DIR%\%2" set /p RESULT=<"%FLAG_DIR%\%2" call :leave_critical_section exit /b :enter_critical_section set /A CRITICAL_SECTION_LEVEL=CRITICAL_SECTION_LEVEL+1 if not [%CRITICAL_SECTION_LEVEL%]==[1] exit /b set /A __WAIT_CNT=500 :wait_enter_critical_section set /A __WAIT_CNT=__WAIT_CNT-1 if [%__WAIT_CNT%]==[0] del "%FLAG_DIR%\$cs$_*" if exist "%FLAG_DIR%\$cs$_*" goto wait_enter_critical_section echo.>"%FLAG_DIR%\$cs$_%UNIQ_BAT_ID%" set /A __CNT=0 for %%i in ( "%FLAG_DIR%\$cs$_*" ) do set /a __CNT=__CNT+1 if [%__CNT%]==[1] goto all_right_1 del "%FLAG_DIR%\$cs$_%UNIQ_BAT_ID%" goto wait_enter_critical_section :all_right_1 exit /b :leave_critical_section set /A CRITICAL_SECTION_LEVEL=CRITICAL_SECTION_LEVEL-1 if [%CRITICAL_SECTION_LEVEL%]==[0] del "%FLAG_DIR%\$cs$_%UNIQ_BAT_ID%" exit /b :EOF

habr.com

Урок batаники - BAT - Программирование - Каталог статей

сочетание %~dp0, которое будет раскрыто в полный путь к каталогу, где находится сценарий. Например,

"%~dp0\packagebin.exe" --recursive-search=yes --files-mask=exe,dll,pdb,obj ^ --archive-type=zip --archive-level=max --deliver-method=ftp ^ --deliver-target=ftp://ftp.site.com --deliver-source="%~dp0\bin"

Обратите внимание на использование кавычек – потенциально каталог может иметь в своем пути пробел. Кавычки избавят от проблем в этом случае.

ПРЕДУПРЕЖДЕНИЕ

Опасайтесь бездумного применения команды cd %~dp0 без проверки результата выполнения. Теоретически, эта команда должна сменить текущий каталог на каталог, в котором расположен командный файл. Как правило, это работает. Однако возможны неожиданности. Однажды был написан простой командный сценарий, задача которого была просто удалить все каталоги рядом с собой. В «свою» директорию он переходил как раз через cd %~dp0. Все было проверено на локальной машине – работало замечательно. После этого сценарий был помещен на файл-сервер, где ему и полагалось быть. Я зашел с помощью Far в сетевой каталог, и для контрольной проверки решил запустить файл еще раз. Дальнейшее словно в тумане. cmd.exe правильно определил местонахождение bat-файла: \\servername\sharename\directory. Однако при попытке сделать туда cd, он сказал, что UNC-пути в качестве текущих каталогов не поддерживаются и лучше он сменит текущий каталог на C:\WINDOWS… Это было действительно мудрое решение… Часть сценария, отвечавшая за удаление всех каталогов, сработала отлично – хорошо, что я успел вовремя остановить это безумие.

В тот день я узнал, что такое System Restore…

Как получить короткое (8.3) имя файла? «А зачем? – спросите вы – Ведь мы живем в мире Интернета, Web-сервисов и NTFS с длинными именами файлов». Это действительно так, но иногда встречаются программы, которые отчаянно сопротивляются прогрессу, и в частности, не любят имен файлов и полных путей с пробелами. Одной из таких программ, кстати, является утилита build.exe из Windows DDK… В таких ситуациях спасает использование короткого, «беспробельного» DOS-имени для файла.

ПРЕДУПРЕЖДЕНИЕ

Доступ к файлу по короткому имени может быть не всегда возможен. На файловой системе NTFS создание коротких псевдонимов для файлов может быть отключено путем установки в единицу значения «NtfsDisable8dot3NameCreation» в ключе реестра «HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\FileSystem».

Итак, все же (в предположении, что надругательства над NTFS не было) – как? Внимательный читатель должен был заметить в предыдущем разделе, что при обращении к переменным %0 - %9 можно использовать префикс

%~s1 - expanded path contains short names only

который нам как раз мог бы помочь. Но есть засада – все эти полезные префиксы нельзя использовать с произвольной переменной окружения, а присваивание переменным %0 - %9 не поддерживается. К счастью, описываемые префиксы можно еще использовать с переменными цикла for, и это дает нам способ достичь требуемого результата. Например, вот так можно получить 8.3-путь к “Program Files”:

for /d %%i in ("%PROGRAMFILES%") do ( set PROGRAMFILESSHORT=%%~si )

echo 8.3-имя для каталога "%PROGRAMFILES%" -^> "%PROGRAMFILESSHORT%"

Этот и другие модификаторы можно использовать и с любой другой формой цикла for, подробнее о которых можно узнать из:

for /?

Как перенаправить стандартный вывод в файл? Плоха та короткая программа, которая не стремится стать большой. К сожалению, это правило применимо и к командным файлам Windows тоже – иногда bat-файлы вырастают до довольно больших размеров. Если при этом результат выполняемых команд должен журналироваться, то все становится совсем плохо – почти каждая строка имеет хвостик типа

echo Cleaning up the target directory >>%LOGFILE% ... echo The target directory has been cleaned >>%LOGFILE%

Гораздо проще было бы перенаправить стандартный вывод в файл, чтобы все команды echo и вообще, все, что выводится на экран, автоматически попадали в журнальный файл. Сделать это можно следующим образом (рассмотрим на знакомом примере генерации HTML-файла):

@echo off set OUTPUT=out.html

if "%STDOUT_REDIRECTED%" == "" ( set STDOUT_REDIRECTED=yes cmd.exe /c %0 %* >%OUTPUT% exit /b %ERRORLEVEL% )

echo ^ echo ^

echo ^^> echo ^^> echo ^ echo Hello World! echo ^^> echo ^^>

Здесь делается то же, что и раньше, но с перенаправлением стандартного вывода в файл out.html. Делается это простым способом – перезапуском сценарием самого себя. Сначала проверяется, не установлена ли переменная окружения STDOUT_REDIRECTED. Если она установлена, значит, сценарий уже перезапущен с перенаправленным выводом и можно просто продолжить работу. Если же переменная не установлена, то мы ее устанавливаем и перезапускаем скрипт (cmd.exe /c %0) с таким же набором параметров, что и исходная команда (%*) и перенаправленным в файл стандартным выводом (>%OUTPUT%). После завершения выполнения «перенаправленной» команды выходим.

Такое «единовременное» перенаправление имеет и еще один неочевидный плюс: файл открывается и закрывается только один раз, и всем командам и дочерним процессам передается дескриптор уже открытого файла. Во-первых, это чуть-чуть улучшит производительность (жизнь удалась – сроду бы не подумал, что буду когда-нибудь писать о производительности в bat-файлах). Во-вторых, это поможет избежать проблемы с невозможностью открыть файл для записи. Такое может случиться, если после выполнения одной из команд останется «висеть» какой-нибудь процесс. Он будет держать дескриптор интересующего нас файла и перенаправление вывода в этот файл для всех последующих команд провалится. Проблема может показаться надуманной, но однажды она украла у меня 2 часа жизни…

Как сложить два числа? Краткий ответ – смотри:

set /?

Длинный ответ таков. В bat-файлах можно производить довольно-таки продвинутые вычисления – продвинутые не в сравнении с другими языками, а в сравнении с отсутствием возможности что-либо вычислить вообще. Вычисление осуществляется командой set, если она выполняется с ключом /a. Поддерживается практически полный набор операторов языка C, включая шестнадцатеричный модификатор 0x. Переменные окружения в выражении не обязательно заключать в знаки процента – все, что не является числом, считается переменной. Подробнее – все-таки в man set, тьфу, то есть в set /?. А здесь напоследок – просто несколько примеров.

@echo off

set ARG=1

rem Переменные окружения в выражении не обязательно заключать в %...% set /a RESULT=ARG + 2 echo %RESULT%

rem Если выражение содержит какие-либо из символов non grata, надо rem заключить его в кавычки set /a RESULT="ARG echo %RESULT%

rem Шестнадцатеричная арифметика set /a RESULT=0x1234 + 0x6786 echo %RESULT%

rem И многое-многое другое...

А можно создать в 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

Как можно избежать использования goto? Любой хоть сколько-то осмысленный *.bat-файл длиной больше 50 строк является ярким лозунгом в поддержку работы Дейкстры «О вреде оператора goto». Мешанина из переходов вперед и назад действительно является кодом «только для записи». Можно ли что-то предпринять по этому поводу?

На самом деле можно. Как правило, большинство меток и переходов используются для организации ветвлений при проверке условий, т.е. банальных if-then-else блоков. В оригинале, bat-язык поддерживал только одну команду в блоке then, что автоматически приводило к идиомам вида:

if condition goto :THEN rem Команды ветки ‘else’ rem ... goto IF_END :THEN rem Команды ветки ‘then’ rem ... :IF_END

Но к счастью, командный интерпретатор cmd.exe современных ОС Windows 2000 и старше поддерживает блоки команд в конструкциях ветвления, что устраняет необходимость применения меток. Блоки команд заключаются в круглые скобки. Выглядит это так (имитируя 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

rem ...

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 у вас встретится закрывающая круглая скобка, то вам необходимо заэкранировать ее символом ^, иначе синтаксический анализатор путается…

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

Как обработать текстовый файл? Иногда в командном файле необходимо получить доступ к содержимому некоторого текстового файла и некоторым образом это содержимое обработать. Например, прочитать файл настроек программы.

Для привнесения еще большей конкретики в процесс изучения зададимся целью прочитать файл с настройками следующего содержания:

# Это простой файл с настройками

# Режим сборки buildmode=release

# Компилятор compiler=cl.exe

# Архитектура arch=x86

Ничего сверхъестественного – простой key=value формат с возможностью вставки Unix-style комментариев. Помочь в чтении и обработке этого файла нам сможет команда for. Ее дополнительные опции позволяют задать и разделители, и символ начала комментария, и кое-что еще. Вот командный файл, который выполняет поставленную задачу:

@echo off

rem Читаем настройки из файла settings.txt, который должен располагаться в rem том же каталоге, что и bat-файл. Если не удалось распарсить настройки - rem выходим с ненулевым кодом возврата. call :read_settings %~dp0\settings.txt || exit /b 1

rem Прочитанные настройки: echo Build mode : %BUILDMODE% echo Compiler : %COMPILER% echo Architecture: %ARCH%

rem Выход из сценария. Дальше - только функции. exit /b 0

rem rem Функция для чтения настроек из файла. rem Вход: rem %1 - Имя файла с настройками :read_settings

set SETTINGSFILE=%1

rem Проверка существования файла if not exist %SETTINGSFILE% ( echo FAIL: Файл с настройками отсутствует exit /b 1 )

rem Обработка файла c настройками rem Здесь: rem eol=# указывает на то, что содержимое строки начиная с символа # rem и до ее конца может быть пропущено как комментарий. rem rem delims== указывает, что разделителем значений является символ = rem rem tokens=1,2 приводит к тому, что в переменную %%i будет занесен первый rem токен, а в %%j - второй. rem

for /f "eol=# delims== tokens=1,2" %%i in (%SETTINGSFILE%) do ( rem В переменной i - ключ rem В переменной j - значение rem Мы транслируем это в переменные окружения set %%i=%%j )

exit /b 0

Обильные комментарии должны помочь легко разобраться, что к чему. За подробностями, как обычно, отошлю к:

for /?

Кстати, возможности команды for не ограничиваются чтением из файла. Возможно также чтение вывода другой команды. Например, так:

@echo off

for /f "tokens=* usebackq" %%i in (`cmd.exe /c ver`) do ( set VERSION=%%i )

echo %VERSION%

Особенно меня умиляет наличие опции “usebackq”, которая делает синтаксис отдаленно похожим на юниксовый. И в стенах царства Билла есть граждане, скучающие по /bin/sh и пытающиеся хоть как-то скрасить существование свое и окружающих. Следующий совет это также косвенно подтверждает.

Что это за упомянутые ранее операторы объединения команд? Это операторы &, && и ||. Они практически совсем не освещены в документации, но полезны в повседневности. Они позволяют объединять несколько команд в одну, т.е. примерно так:

command1 & command2 command1 && command2 command1 || command2

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

command1 command2

Оператор && гарантирует, что вторая команда будет выполнена только, если первая была выполнена успешно, т.е. с нулевым кодом возврата (он же %errorlevel%). Такие конструкции очень популярны в мире shell-сценариев Unix. Например:

cd sources && make clean

Я был приятно удивлен, узнав, что cmd.exe тоже умеет выполнять такие конструкции. Это безопаснее и правильнее, нежели простое последовательное выполнение этих команд, и короче и проще, чем строгая проверка и обработка кодов возврата. Очень удобно при написании на скорую руку. Не менее полезен иногда и оператор ||. Суть его тоже логична – выполнить вторую команду, если первая дала сбой. Часто встречается в таких идиомах:

cd sources || exit 1

Если перейти в каталог sources не удастся, то будет произведен выход с кодом ошибки 1. Если же первая команда отработает нормально, то вторая выполнена не будет. Например, такая простейшая защита помогла бы в случае с cd по UNC-адресу, описанному ранее.

Можно ли написать на bat-языке серьезную программу? Пожалуй, нет. Серьезная программа должна все-таки выглядеть серьезно. А все написанное на командном языке Windows таковым назвать можно лишь с о-о-о-чень большой натяжкой. Так что для решения более сложных задач автоматизации лучше все-таки взять что-нибудь более функциональное:

Perl Python Ruby JScript / VBScript Последние, кстати, присутствуют в Windows 2000/XP по умолчанию (с некоторыми функциональными различиями) и в целом могут считаться заменой *.bat языку. Однако сдается мне, что *.bat-файлы проживут еще очень долго.

Дай Бог, чтобы я ошибся…

_______________________ inattack.ru

Источник: http://www.inattack.ru/article/385.html

sgw32.ucoz.ru

Использование bat файлов для создания «Заданий по расписанию» / Хабр

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

Наверняка многие сталкивались с задачей, когда для каких-либо целей в ОС Windows необходимо создать задание, выполняемое по расписанию (scheduled task). Для этих целей имеется простой графический интерфейс. Однако как поступить, если задание должно создаваться автоматически? Попробуем решить эту задачу с использованием примитивного bat-скрипта, который будет выполняться в практически любой версии Windows. Для удобства, создадим на машине локального технологического пользователя, под которым будет работать наше задание по расписанию. Это удобно тем, что для пользователя можно задать права, которые необходимы только для выполнения определенных действий.

:: Имя локального пользователя, под которым будем работатьset user_name=test_user :: Пароль для локального пользователяset user_passw=test_passw

А как известно пользователь должен находиться в группе с определенными правами. Вот тут и возникает определенная сложность, т.к. если в скрипте четко задать имя группы, то могут возникнуть проблемы на машине с другой локализацией, например китайской. И как будет называться на китайском группа «Пользователи» узнать будет не очень просто. К счастью, в ОС Windows группы привязаны к так называемому Group SID. Зная, к примеру, Group SID группы «Администраторы», мы можем использовать его в скрипте. Например, S-1-5-32-545 — это локальные пользователи, а S-1-5-32-544 — администраторы. Теперь нужно определить имя для заданного Group SID, используемого в данной локализации. Тут нам на помощь придет WMIC (WMI command-line).

:: S-1-5-32-545 - локальные пользователи Set GroupSID=S-1-5-32-545 Set GroupName= For /F "UseBackQ Tokens=1* Delims==" %%I In (`WMIC Group Where "SID = '%GroupSID%'" Get Name /Value ^| Find "="`) Do Set GroupName=%%J Set GroupName=%GroupName:~0,-1%

Нужно знать еще один нюанс. При создании пользователя, в зависимости от системных настроек, задается время истечения пароля. И если пароль нужно будет поменять, то задание по расписанию не будет выполняться. Для этого нам нужно создать пользователя, у которого никогда не истекает пароль. Задать это в стандартной команде net user нельзя (expires:never — задает, что пользователь не может поменять пароль), поэтому опять прибегнем к помощи WMIC:

:: Создание пользователя net user %user_name% %user_passw% /add  /comment:"User for works with application" /expires:never /fullname:%user_name% /passwordchg:no :: Устанавливаем, чтобы пароль не истекал никогда :: Либо так - wmic path Win32_UserAccount where Name='%user_name%' set PasswordExpires=false wmic USERACCOUNT where Name='%user_name%' set PasswordExpires=false :: Добавление локального пользователя в заданную локальную группу net localgroup %GroupName% %user_name% /ADD

Обратите внимание, что если вы удаляете пользователя командой net user test_user /DELETE, то вам нужно будет вручную удалить его каталог по пути %USERS%\test_user\ либо предусмотреть его удаление в скрипте.

Ну а далее создаем само задание, выполняемое по расписанию:

:: Имя запланированного задания, под которым будет работать приложениеset task_name=Test_task_bat :: Путь к приложениюset my_app_path="d:test.bat" :: Интервал работы приложения во временном задании ::  Valid schedule types: MINUTE, HOURLY, DAILY, WEEKLY, MONTHLY, ONCE, ONSTART, ONLOGON, ONIDLE. :: ЕЖЕМИНУТНО, ЕЖЕЧАСНО, ЕЖЕДНЕВНО, ЕЖЕНЕДЕЛЬНО, ЕЖЕМЕСЯЧНО ПРИ ЗАПУСКЕ ВХОДЕ В СИСТЕМУ ПРИ ПРОСТОЕset schtasks_time=MINUTE :: Начальное время старта приложения во временном заданииset schtasks_start=08:00:00   :: Создание запланированного задания schtasks /create /tn "%task_name%" /tr %my_app_path% /sc %schtasks_time% /st %schtasks_start% /ru %user_name% /rp %user_passw%

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

P.S. Предвижу подобные вопросы и комментарии: есть же более удобные инструменты, почему именно bat? Just for fun!

habr.com

Bat-программирование для работы с файлами

Documents войти Загрузить ×
  1. Общественные науки
  2. Политология
  3. Медиа
advertisement advertisement
Related documents
Лабораторная 7 Дополнительные материалы
АНТИВИРУС «ИММУНИТЕТ»
Bat-программирование для организации вычислений
“Введение в информационные технологии”
Летние каникулы в Англии с «DESTINATION» Международный
Занятие 5.
Echo3G Windows Manual
Работа с командным интерфейсом. Пакетные командные файлы
Состязания на лучшую команду информатиков
Echo3G Mac Manual
Media Kit EXIST 2011
Практическая работа №15
Вторичная структура тРНК глутамина из Escherichia coli
Установка АСИОУ 7.0 под Linux

studydoc.ru

Dr.Batcher для создания bat-файлов — пк-ГИД

Всем, кто начинал осваивать компьютерные технологии ещё со времён операционной системы DOS, наверняка знакомы пакетные BAT-файлы. Сегодня они используются не так широко, как в старые времена. Однако для многих задач использование пакетного файла бывает более эффективно, чем создание установочного дистрибутива. Dr.Batcher представляет собой визуальный редактор для bat-файлов. С помощью этой программы можно создавать и редактировать пакетные файлы, пользуясь такими уже привычными для многих языков программирования функциями, как подсветка синтаксиса, подсказки, параметры команд, нумерация строк и закладки.

Dr.Batcher позволяет начать работу как с чистого листа, так и с редактирования уже существующего bat-файла. Начнём с готового примера, который можно найти в папке Examples, где установлена программа. На рисунке хорошо видно, как код оформлен различными шрифтами и цветами, что сильно повышает его читаемость.

Для проверки выполнения bat-файла достаточно нажать кнопку [Execute] (исполнение в окне программы) или [Execute in External Windows] (запуск скрипта в отдельном окне). Любители клавиатурных комбинаций нажимают F9 или Ctrl + F9. Для проверки запустим bat-файл под названием Matrix.bat в отдельном окне. Этот пакетный файл создан с одной целью – имитация эффекта матрицы из одноимённого фильма.

Кстати, этот сценарий может выполняться бесконечно, так что для остановки нажимаем клавиши Ctrl + C.

Dr.Batcher отображает скрипт пакетного bat-файла в двух режимах (меню View):Simple Mode – режим для начинающих, где вместо команды отображается краткое описание её назначения, переключается также клавишей F11.Professional Mode – профессиональный режим, когда мы видим команды в правильном виде, включается клавишей F12.

Для редактирования кода предусмотрена отдельная панель инструментов, отображающаяся в упрощённом режиме Simple Mode:1. Add Command – добавить строку с командой;2. Insert Command – вставить команду перед выбранной строкой;3. Remove Command – удалить выделенную строку;4. Edit Command – редактировать выбранную строку;5. Move Up – переместить строку на одну позицию вверх;6. Move Down – переместить строку на одну позицию вниз;7. Move on Top – перенести строку в самое начало;8. Move to Bottom – перенести строку в конец пакетного файла.

При добавлении или вставке новой команды Dr.Batcher предлагает нам выбрать команду из списка. Клик на команде в списке открывает её подробное описание.

Многие команды вводятся с дополнительными параметрами. Если выбрана именно такая команда, то программа будет ждать ввода параметров в отдельном окне. Для удобства здесь предусмотрены две кнопки:[Information on command…] – информация о команде, где приведено общее описание команды и параметров, необходимых для неё. Если минимальное количество параметров равно 1 или больше, это значит, что с командой обязательно должен идти параметр, в противном случае можно указать только команду.

[Information on parameter…] – информация о параметрах команды. Приведены все возможные их значения и описание. Например, для команды color доступны следующие значения:

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

Например, вот как будет выполнен следующий пакетный файл:CLS COLOR 4 MKDIR c:\PKGID PAUSE

Здесь первая команда CLS очищает экран (все ранее введённые команды), затем устанавливается красный цвет символов (COLOR 4), потом создаётся папка (MKDIR) под названием PKGID на диске C, после чего скрипт переходит в режим ожидания, задаваемый командой PAUSE.

Для тестирования скриптов прямо из программы можно запустить Командную строку (Batch – Run Command Prompt). Такой подход многим покажется удобнее и привычнее, ведь изначально bat-файлы исполнялись именно в командной строке.

Созданные скрипты можно экспортировать в HTML, RTF и TeX с сохранением подсветки синтаксиса. К тому же, Dr.Batcher поддерживает как DOS- так и Windows-кодировку.

Мы не сможем рассмотреть в рамках этой статьи все возможные команды, используемые в bat-файлах. В помощь придёт справка программы и возможность поиска информации по использованию команд через Google, Yahoo и MSN Search. Тем не менее, рассмотренные примеры наверняка помогут начать освоение редактора пакетных файлов Dr.Batcher.

Характеристики:Язык интерфейса: английскийОС: Windows 2000, XP, Vista, 7Размер файла: 5,15 МбЛицензия: условно-бесплатная, регистрация 39.95$.

www.pkgid.ru

Ненормальное программирование / Использование bat файлов для создания «Заданий по расписанию»

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

Наверняка многие сталкивались с задачей, когда для каких-либо целей в ОС Windows необходимо создать задание, выполняемое по расписанию (scheduled task).Для этих целей имеется простой графический интерфейс. Однако как поступить, если задание должно создаваться автоматически?Попробуем решить эту задачу с использованием примитивного bat-скрипта, который будет выполняться в практически любой версии Windows.Для удобства, создадим на машине локального технологического пользователя, под которым будет работать наше задание по расписанию. Это удобно тем, что для пользователя можно задать права, которые необходимы только для выполнения определенных действий.

:: Имя локального пользователя, под которым будем работатьset user_name=test_user:: Пароль для локального пользователяset user_passw=test_passw

А как известно пользователь должен находиться в группе с определенными правами. Вот тут и возникает определенная сложность, т.к. если в скрипте четко задать имя группы, то могут возникнуть проблемы на машине с другой локализацией, например китайской. И как будет называться на китайском группа «Пользователи» узнать будет не очень просто. К счастью, в ОС Windows группы привязаны к так называемому Group SID. Зная, к примеру, Group SID группы «Администраторы», мы можем использовать его в скрипте. Например, S-1-5-32-545 — это локальные пользователи, а S-1-5-32-544 — администраторы.Теперь нужно определить имя для заданного Group SID, используемого в данной локализации. Тут нам на помощь придет WMIC (WMI command-line).

:: S-1-5-32-545 - локальные пользователиSet GroupSID=S-1-5-32-545Set GroupName=For /F "UseBackQ Tokens=1* Delims==" %%I In (`WMIC Group Where "SID = '%GroupSID%'" Get Name /Value ^| Find "="`) Do Set GroupName=%%JSet GroupName=%GroupName:~0,-1%

Нужно знать еще один нюанс. При создании пользователя, в зависимости от системных настроек, задается время истечения пароля. И если пароль нужно будет поменять, то задание по расписанию не будет выполняться. Для этого нам нужно создать пользователя, у которого никогда не истекает пароль. Задать это в стандартной команде net user нельзя (expires:never — задает, что пользователь не может поменять пароль), поэтому опять прибегнем к помощи WMIC:

:: Создание пользователяnet user %user_name% %user_passw% /add  /comment:"User for works with application" /expires:never /fullname:%user_name% /passwordchg:no:: Устанавливаем, чтобы пароль не истекал никогда:: Либо так - wmic path Win32_UserAccount where Name='%user_name%' set PasswordExpires=falsewmic USERACCOUNT where Name='%user_name%' set PasswordExpires=false:: Добавление локального пользователя в заданную локальную группуnet localgroup %GroupName% %user_name% /ADD

Обратите внимание, что если вы удаляете пользователя командой net user test_user /DELETE, то вам нужно будет вручную удалить его каталог по пути %USERS%test_user либо предусмотреть его удаление в скрипте.

Ну а далее создаем само задание, выполняемое по расписанию:

:: Имя запланированного задания, под которым будет работать приложениеset task_name=Test_task_bat:: Путь к приложениюset my_app_path="d:test.bat":: Интервал работы приложения во временном задании::  Valid schedule types: MINUTE, HOURLY, DAILY, WEEKLY, MONTHLY, ONCE, ONSTART, ONLOGON, ONIDLE.:: ЕЖЕМИНУТНО, ЕЖЕЧАСНО, ЕЖЕДНЕВНО, ЕЖЕНЕДЕЛЬНО, ЕЖЕМЕСЯЧНО ПРИ ЗАПУСКЕ ВХОДЕ В СИСТЕМУ ПРИ ПРОСТОЕset schtasks_time=MINUTE:: Начальное время старта приложения во временном заданииset schtasks_start=08:00:00 :: Создание запланированного заданияschtasks /create /tn "%task_name%" /tr %my_app_path% /sc %schtasks_time% /st %schtasks_start% /ru %user_name% /rp %user_passw%

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

P.S. Предвижу подобные вопросы и комментарии: есть же более удобные инструменты, почему именно bat? Just for fun!

Автор: ngelik

www.pvsm.ru