Продолжаю предложенную sqltd1 рубрику под названием "психоделическое программирование". Сегодня я подумал - вот в Python есть import, в C и C++ #include, в Node.JS - require. И так далее - почти во всех ЯП есть возможность подключить в свой код внешний файл и использовать функции и переменные оттуда.
Но что в Batch?
А в Batch - как обычно, на первый взгляд ничего, но дело в том, что есть у него одна особенность - код bat-файлов можно редактировать во время выполнения.
Убедиться в этом нетрудно - просто создайте bat-файл, который, к примеру, каждую секунду выводит в консоль единицу:
| Windows Batch file | 1
2
3
4
5
6
| @echo off
:loop
echo 1
timeout /t 1 /nobreak > nul
goto loop |
|
Теперь запустите это "чудо инженерной мысли", убедитесь, что оно работает, и, не закрывая окно cmd, где этот батник исполняется, откройте его в текстовом редакторе, замените единицу на двойку и сохраните файл.
Помимо того, что система дает вам это сделать, взглянув на окно cmd, вы увидите там двойки - изменененный код выполняется.
А раз можно заменить команду - почему бы не добавить в код bat-файла некоторые подпрограммы?
Для этого отлично подойдет команда copy - она позволяет "склеить" два файла в один:
| Windows Batch file | 1
| copy input1.txt+input2.txt output.txt |
|
Но у нее есть одна особенность - в текстовые файлы она вставляет управляющий символ, а значит нужен ключ /b, который переключает copy в режим бинарных файлов, в котором она ничего не вставляет.
Например:
main.bat
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| @echo off
:: Проверка, включен ли код библиотеки в файл
call :lib_test 2> nul
:: Если нет, включаем
if not %ERRORLEVEL%==0 (
copy /b "%~f0"+"lib.bat" "%~f0" > nul
)
:: Вызов подпрограммы из библиотеки
call :add 2 3 result
echo %result%
:: Выход, чтобы код из подпрограмм не выполнялся до вызова
exit /b |
|
lib.bat
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
11
| :: Сверху обязательно пустая строка!
:: Пустая подпрограмма для проверки того, вставлена ли библиотека в файл
:lib_test
rem
goto :eof
:: Пример подпрограммы сложения двух чисел
:add [a] [b] [result]
set /a "%~3=%~1+%~2"
goto :eof |
|
При первом запуске файла main.bat в него добавится код из lib.bat, и, соответственно, можно будет вызывать подпрограммы из него.
Для большего удобства я создал подпрограмму import, которая автоматизирует подключение библиотек:
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| :import [type] [name] [libname]
if "%~3"=="" ( set "libname=%~n2" ) else ( set "libname=%~3" )
call :%libname% 2> nul
if %ERRORLEVEL%==0 goto :eof
if "%~1"=="file" (
copy /b "%~f0"+"%~f2" "%~f0" > nul
) else if "%~1"=="url" (
curl -so "%temp%\%libname%.bak" "%~2"
copy /b "%~f0"+"%temp%\%libname%.bak" "%~f0" > nul
del "%temp%\%libname%.bak" > nul
) else if "%~1"=="repo" (
curl -so "%temp%\%libname%.bak" "%REPOSITORY_URL%/%libname%.bat"
copy /b "%~f0"+"%temp%\%libname%.bak" "%~f0" > nul
del "%temp%\%libname%.bak" > nul
)
goto :eof |
|
Помимо импорта из файла, данная подпрограмма также способна загружать библиотеки по URL и из репозитория по названию.
Проверка, включена ли уже библиотека, осуществляется следующим образом:- Если библиотека импортируется из файла, проверяется подпрограмма с таким же названием, как у файла (но без расширения): например, файл D:\lib\test.bat должен содержать подпрограмму test
- Если библиотека импорируется из репозитория, название подпрограммы должно соответствовать названию библиотеки
- Если библиотека импортируется по URL, указать название подпрограммы требуется указать вручную 3-м параметром import
Примечание: если 3-й параметр указан, import будет игнорировать автоматическое определение подпрограммы для вызова и использовать в качестве этого названия значение параметра.
Примеры:
main.bat
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| @echo off
:: URL репозитория
set "REPOSITORY_URL=https://example.com/bat-repo"
:: Импорт из файла
call :import file "D:\lib\lib1.bat"
:: Импорт по URL
call :import url "https://example.com/lib2.bat" lib2
:: Импорт из репозитория
call :import repo lib3
:: Вызов подпрограмм из библиотек
call :proc1
call :proc2
call :proc3
exit /b
:import [type] [name] [libname]
if "%~3"=="" ( set "libname=%~n2" ) else ( set "libname=%~3" )
call :%libname% 2> nul
if %ERRORLEVEL%==0 goto :eof
if "%~1"=="file" (
copy /b "%~f0"+"%~f2" "%~f0" > nul
) else if "%~1"=="url" (
curl -so "%temp%\%libname%.bak" "%~2"
copy /b "%~f0"+"%temp%\%libname%.bak" "%~f0" > nul
del "%temp%\%libname%.bak" > nul
) else if "%~1"=="repo" (
curl -so "%temp%\%libname%.bak" "%REPOSITORY_URL%/%libname%.bat"
copy /b "%~f0"+"%temp%\%libname%.bak" "%~f0" > nul
del "%temp%\%libname%.bak" > nul
)
goto :eof |
|
lib1.bat (локальный файл)
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
| :: Сверху пустая строка
:: Проверка
:lib1
rem
goto :eof
:proc1
echo Proc1
goto :eof |
|
lib2.bat (URL)
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
| :: Сверху пустая строка
:: Проверка
:lib2
rem
goto :eof
:proc2
echo Proc2
goto :eof |
|
lib3.bat (из репозитория)
| Windows Batch file | 1
2
3
4
5
6
7
8
9
10
| :: Сверху пустая строка
:: Проверка
:lib3
rem
goto :eof
:proc3
echo Proc3
goto :eof |
|
Также, я создал репозиторий для bat-библиотек.
Чтобы его использовать:
| Windows Batch file | 1
| set "REPOSITORY_URL=https://nekit270.ch/bat_repo" |
|
Загрузить свою библиотеку: https://nekit270.ch/bat_repo/upload.html
Получить список библиотек в репозитории: https://nekit270.ch/bat_repo/list.php
|