Windows.bat/.cmd библиотека функций в собственном файле?
есть отличный способ создания функций в DOS.bat/.cmd script. Для модуляции некоторых сценариев установки было бы неплохо включить файл с библиотекой функций в .bat/.cmd script.
Я пытался:
mainscript.bat
call library.bat
call:function1
library.bat
goto:eof
:stopCalipri -- stop alle prozesse die mit calipri zu tun haben
:: -- %~1: argument description here
SETLOCAL
REM.--function body here
set LocalVar1=dummy
set LocalVar2=dummy
echo "Called function successfully :)"
(ENDLOCAL & REM -- RETURN VALUES
IF "%~1" NEQ "" SET %~1=%LocalVar1%
IF "%~2" NEQ "" SET %~2=%LocalVar2%
)
GOTO:EOF
Когда я вызываю mainscript.bat, я получаю следующий вывод:
Das Sprungziel - function1 wurde nicht gefunden.
Что означает больше или меньше: не удается найти точку перехода с именем function1
Любые идеи, или это невозможно?
Ответы
Ответ 1
Это возможно, и есть несколько способов сделать это.
1) Копировать & Вставить полную "Библиотеку" в каждый из ваших файлов
Работает, но это не настоящая библиотека, и это ужас для изменения/исправления библиотечной функции во всех файлах.
2) включают библиотеку через оболочку вызова
call batchLib.bat :length result "abcdef"
и batchLib.bat начинается с
call %*
exit /b
...
:length
...
Простота программирования, но очень медленная, так как каждый вызов библиотеки загружает пакет библиотеки и возможные проблемы с параметрами.
3) Библиотека "self-loading" BatchLibrary или включение пакетных файлов
Он создает каждый раз временный командный файл, объединенный с собственным кодом и кодом библиотеки.
Он выполняет некоторые дополнительные функции при запуске библиотеки, например, безопасный доступ к параметрам.
Но, на мой взгляд, он также прост в использовании
Пользователь script образец
@echo off
REM 1. Prepare the BatchLibrary for the start command
call BatchLib.bat
REM 2. Start of the Batchlib, acquisition of the command line parameters, activates the code with the base-library
<:%BL.Start%
rem Importing more libraries ...
call :bl.import "bl_DateTime.bat"
call :bl.import "bl_String.bat"
rem Use library functions
call :bl.String.Length result abcdefghij
echo len=%result%
РЕДАКТИРОВАТЬ: Еще один способ...
4) Макро библиотека
Вы можете использовать пакетные макросы, их легко включить и использовать.
call MacroLib.bat
set myString=abcdef
%$strLen% result,myString
echo The length of myString is %result%
Но сложно построить макросы!
Подробнее о макротехнике в Пакетные макросы с аргументами
MacroLibrary.bat
set LF=^
::Above 2 blank lines are required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
:::: StrLen pString pResult
set $strLen=for /L %%n in (1 1 2) do if %%n==2 (%\n%
for /F "tokens=1,2 delims=, " %%1 in ("!argv!") do (%\n%
set "str=A!%%~2!"%\n%
set "len=0"%\n%
for /l %%A in (12,-1,0) do (%\n%
set /a "len|=1<<%%A"%\n%
for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"%\n%
)%\n%
for %%v in (!len!) do endlocal^&if "%%~b" neq "" (set "%%~1=%%v") else echo %%v%\n%
) %\n%
) ELSE setlocal enableDelayedExpansion ^& set argv=,
Ответ 2
Существует более простой способ загрузки библиотечных функций каждый раз, когда выполняется основной файл. Например:
@echo off
rem If current code was restarted, skip library loading part
if "%_%" == "_" goto restart
rem Copy current code and include any desired library
copy /Y %0.bat+lib1.bat+libN.bat %0.full.bat
rem Set the restart flag
set _=_
rem Restart current code
%0.full %*
:restart
rem Delete the restart flag
set _=
rem Place here the rest of the batch file
rem . . . . .
rem Always end with goto :eof, because the library functions will be loaded
rem after this code!
goto :eof
Ответ 3
Я придумал простое решение для использования внешних библиотек с пакетными файлами, и я хотел бы попросить вас, ребята, проверить его и найти возможные ошибки.
Как использовать:
- Создайте библиотеку (папка с библиотечными пакетными файлами внутри)
- Поместите этот заголовок перед созданием какого-либо командного файла, который использует библиотеку.
Принцип работы:
Как это работает:
- Создает временный файл в% TEMP% (не работает, если% TEMP% не установлено)
- Копирует себя во временный файл
- Ищет каждую библиотеку на этих путях:
- исходный путь пакетного файла
- % BatchLibraryPath%
- Любой другой путь, указанный в% _IncludesPath%
- Добавляет эти библиотеки во временный файл
- Запускает временный файл
- завершает и удаляет временный файл
Преимущества:
- Прошли аргументы командной строки
- Не нужно заканчивать код пользователя какой-либо специальной командой
- Библиотеки могут быть в любом месте на компьютере.
- Библиотеки могут находиться в общих папках с UNC-путями
- У вас могут быть библиотеки на разных путях, и все они будут добавлены (если одна и та же библиотека найдена в разных путях, используется один из левого пути в% _IncludesPath%)
- Возвращает уровень ошибок, если возникла какая-либо ошибка.
код:
- Вот пример: для этого вы должны иметь библиотеку Example.bat в папке Your_batch_file.bat(или в одной из папок% _IncludesPath%)
Your_batch_file.bat
@echo off & setlocal EnableExtensions
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::Your code starts in :_main
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: v1.5 - 01/08/2015 - by Cyberponk - Fixed returning to original path when using RequestAdminElevation
:: v1.4 - 25/05/2015 - by Cyberponk
:: This module includes funcions from included libraries so that you can call
:: them inside the :_main program
::
:: Options
set "_DeleteOnExit=0" &:: if 1, %_TempFile% will be deleted on exit (set to 0 if using library RequestAdminElevation)
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
(if "%BatchLibraryPath%"=="" set "BatchLibraryPath=.") &set "_ErrorCode=" &set "#include=call :_include"
set _LibPaths="%~dp0";"%BatchLibraryPath%"&set "_TempFile=%TEMP%\_%~nx0"
echo/@echo off ^& CD /D "%~dp0" ^& goto:_main> "%_TempFile%" || (echo/Unable to create "%_TempFile%" &echo/Make sure the %%TEMP%% path has Read/Write access and that a file with the same name doesn't exist already &endlocal &md; 2>nul &goto:eof ) &type "%~dpf0" >> "%_TempFile%" &echo/>>"%_TempFile%" &echo goto:eof>>"%_TempFile%" &call :_IncludeLibraries
(if "%_ErrorCode%"=="" (call "%_TempFile%" %*) else (echo/%_ErrorCode% &pause)) & (if "%_DeleteOnExit%"=="1" (del "%_TempFile%")) & endlocal & (if "%_ErrorCode%" NEQ "" (set "_ErrorCode=" & md; 2>nul)) &goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:_include lib
set "lib=%~1.bat" &set "_included="
(if EXIST "%lib%" ( set "_included=1" &echo/>> "%_TempFile%" &type "%lib%" >> "%_TempFile%" & goto:eof )) & for %%a in (%_LibPaths%) do (if EXIST "%%~a\%lib%" ( set "_included=1" &echo/>> "%_TempFile%" &type "%%~a\%lib%" >> "%_TempFile%" &goto:endfor))
:endfor
(if NOT "%_included%"=="1" ( set "_ErrorCode=%_ErrorCode%Library '%~1.bat' not fount, aborting...&echo/Verify if the environment variable BatchLibraryPath is pointing to the right path - and has no quotes - or add a custom path to line 25&echo/" )) &goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:_IncludeLibraries - Your included libraries go here
::::::::::::::::::::::::::::::::::::::
:: You can add custom paths to this variable:
set _LibPaths=%_LibPaths%; C:\; \\SERVER\folder
:: Add a line for each library you want to include (use quotes for paths with space)
:: Examples:
:: %#include% beep
:: %#include% Network\GetIp
:: %#include% "Files and Folders\GetDirStats"
:: %#include% "c:\Files and Folders\GetDriveSize"
:: %#include% "\\SERVER\batch\SendHello"
%#include% Example
goto:eof
::End _IncludeLibraries
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:_main - Your code goes here
::::::::::::::::::::::::::::::::::::::
echo/Example code:
call :Example "It works!"
echo/____________________
echo/Work folder: %CD%
echo/
echo/This file: %0
echo/
echo/Library paths: %_LibPaths%
echo/____________________
echo/Argument 1 = %1
echo/Argument 2 = %2
echo/All Arguments = %*
echo/____________________
pause
.
Example.bat
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Example msg
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEEXTENSIONS & set "msg=%1"
echo/%msg%
endlocal & goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Если вам нужен простой способ установить% BatchLibraryPath%, просто поместите этот файл в свой путь к библиотеке и запустите его перед запуском Your_batch_file.bat.
Этот параметр является постоянным при перезагрузках, поэтому вы запускаете только один раз:
SetBatchLibraryPath.bat
setx BatchLibraryPath "%~dp0"
pause
Ответ 4
Другим решением будет временное добавление функций библиотеки к запущенному пакетному файлу.
Оригинальный файл можно сохранить во временном файле перед изменением и восстановить по завершении.
Это имеет недостаток, что вам нужно вызвать функцию: deimport в конце, чтобы восстановить файл и удалить временный файл. Вы также должны иметь возможность писать в пакетный файл и папку, в которой вы сейчас находитесь.
demo.bat
@ECHO OFF
:: internal import call or external import call via wrapper function
CALL:IMPORT test.bat "C:\path with spaces\lib 2.bat"
:: external import call
::CALL importer.bat "%~f0%" test.bat "C:\path with spaces\lib 2.bat"
CALL:TEST
CALL:LIB2TEST
CALL:DEIMPORT
GOTO:EOF
:: Internal version of the importer
:IMPORT
SETLOCAL
IF NOT EXIST "%~f0.tmp" COPY /Y "%~f0" "%~f0.tmp">NUL
SET "PARAMS=%*"
SET "PARAMS=%PARAMS:.bat =.bat+%"
SET "PARAMS=%PARAMS:.bat" =.bat"+%"
COPY /Y "%~f0"+%PARAMS% "%~f0">NUL
ENDLOCAL
GOTO:EOF
:: wrapper function for external version call
:::IMPORT
::CALL import.bat "%~f0" %*
::GOTO:EOF
:: Internal version of the deimporter
:DEIMPORT
IF EXIST "%~f0.tmp" (
COPY /Y "%~f0.tmp" "%~f0">NUL
DEL "%~f0.tmp">NUL
)
GOTO:EOF
test.bat
:test
ECHO output from test.bat
GOTO:EOF
C:\путь с пробелами \lib 2.bat
:LIB2TEST
ECHO output from lib 2.bat
GOTO:EOF
Альтернативно используется внешняя версия. Обратите внимание, что это импортирует функцию deimport, поэтому убедитесь, что вы удалили ее в файле demo.bat.
import.bat
:: External version of the importer
SETLOCAL EnableDelayedExpansion
IF NOT EXIST "%~f1.tmp" COPY /Y "%~f1" "%~f1.tmp">NUL
SET "PARAMS=%*"
SET "PARAMS=!PARAMS:"%~f1" =!"
SET "PARAMS=%PARAMS:.bat =.bat+%"
SET "PARAMS=%PARAMS:.bat" =.bat"+%"
COPY /Y "%~f1"+%PARAMS% "%~f1">NUL
:: external version of the importer - remove the internal one before use!
ECHO :DEIMPORT>>"%~f1"
ECHO IF EXIST ^"%%~f0.tmp^" ^(>>"%~f1"
ECHO. COPY /Y ^"%%~f0.tmp^" ^"%%~f0^"^>NUL>>"%~f1"
ECHO. DEL ^"%%~f0.tmp^"^>NUL>>"%~f1"
ECHO ^)>>"%~f1"
ECHO GOTO:EOF>>"%~f1"
ENDLOCAL
GOTO:EOF
Ответ 5
ладно... быстро и грязно, потому что я парень UNIX...
создайте файл "library"
1 @ECHO OFF<br>
2 SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION & PUSHD<br>
3 :: -----------------------------------------------<br>
4 :: $Id$<br>
5 :: <br>
6 :: NAME:<br>
7 :: PURPOSE:<br>
8 :: NOTES:<br>
9 :: <br>
10 :: INCLUDES --------------------------------- --<br>
11 :: DEFINES --------------------------------- --<br>
12 :: VARIABLES --------------------------------- --<br>
13 :: MACROS --------------------------------- --<br>
14 <br>
15 GOTO :MAINLINE<br>
16 <br>
17 :: FUNCTIONS --------------------------------- --<br>
18 <br>
19 :HEADER<br>
20 ECHO ^<HTML^><br>
21 ECHO ^<HEAD^><br>
22 ECHO ^<TITLE^>%1^</TITLE^><br>
23 ECHO ^</HEAD^><br>
24 ECHO ^<BODY^><br>
25 GOTO :EOF<br>
26 <br>
27 :TRAILER<br>
28 ECHO ^</BODY^><br>
29 ECHO ^</HTML^><br>
30 GOTO :EOF<br>
31 <br>
32 :: MAINLINE --------------------------------- --<br>
33 :MAINLINE<br>
34 <br>
35 IF /I "%1" == "HEADER" CALL :HEADER %2<br>
36 IF /I "%1" == "TRAILER" CALL :TRAILER<br>
37 <br>
38 ENDLOCAL & POPD<br>
39 :: HISTORY ------------------------------------<br>
40 :: $Log$<br>
41 :: END OF FILE --------------------------------- --<br>
это должно быть довольно прямолинейно для вас... в строке 15 мы делаем переход к mainline, чтобы начать фактическое выполнение. На строках 19 и 27 мы создаем точки входа для наших подпрограмм. На строках 35 и 36 - вызовы внутренних процедур.
теперь вы создаете файл, который будет вызывать библиотечные процедуры.
1 @ECHO OFF<br>
2 SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION & PUSHD<br>
3 :: -----------------------------------------------<br>
4 :: $Id$<br>
5 :: <br>
6 :: NAME:<br>
7 :: PURPOSE:<br>
8 :: NOTES:<br>
9 :: <br>
10 :: INCLUDES --------------------------------- --<br>
11 <br>
12 SET _LIB_=PATH\TO\LIBRARIES\LIBNAME.BAT<br>
13 <br>
14 :: DEFINES --------------------------------- --<br>
15 :: VARIABLES --------------------------------- --<br>
16 :: MACROS --------------------------------- --<br>
17 <br>
18 GOTO :MAINLINE<br>
19 <br>
20 :: FUNCTIONS --------------------------------- --<br>
21 :: MAINLINE --------------------------------- --<br>
22 :MAINLINE<br>
23 <br>
24 call %_LIB_% header foo<br>
25 call %_LIB_% trailer<br>
26 <br>
27 ENDLOCAL & POPD<br>
28 :: HISTORY ------------------------------------<br>
29 :: $Log$<br>
30 :: END OF FILE --------------------------------- --<br>
<br>
строка 12 "импортирует" "библиотеку"... на самом деле это просто синтаксический сахар, который упрощает последующие вызовы...