Windows .bat/.cmd 函数库在自己的文件中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7712661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Windows .bat/.cmd function library in own file?
提问by andreas
there is a nice way to build functionsin DOS .bat/.cmd script. To modularize some installation scripts, it would be nice to include a file with a library of functions into an .bat/.cmd script.
有一种在 DOS .bat/.cmd 脚本中构建函数的好方法。要模块化某些安装脚本,最好将带有函数库的文件包含到 .bat/.cmd 脚本中。
what I tried was:
我试过的是:
mainscript.bat
主脚本.bat
call library.bat
call:function1
library.bat
图书馆.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
When I call mainscript.bat then I get following output: Das Sprungziel - function1 wurde nicht gefunden.
当我调用 mainscript.bat 时,我得到以下输出:Das Sprungziel - function1 wurde nicht gefunden。
What means more or less: Can not find jump point named function1
或多或少是什么意思:找不到名为function1的跳转点
Any ideas, or is this not possible?
任何想法,或者这是不可能的?
采纳答案by jeb
It's possible, and there are some different ways to do it.
这是可能的,并且有一些不同的方法可以做到。
1) Copy&Paste the complete "Library" into each of your files Works, but it's not really a library, and it's a horror to change/correct a library function in all files
1)将完整的“库”复制并粘贴到您的每个文件中 有效,但它并不是真正的库,并且更改/更正所有文件中的库函数是一种恐怖
2) include a library via call-wrapper
2)通过调用包装器包含一个库
call batchLib.bat :length result "abcdef"
and batchLib.bat starts with
和 batchLib.bat 以
call %*
exit /b
...
:length
...
Easy to program, but very slow, as each library call loads the library batch, and possible problems with the parameters.
易于编程,但速度很慢,因为每个库调用都会加载库批处理,并且参数可能存在问题。
3) A "self-loading" library BatchLibrary or how to include batch files(cached)
3)“自加载”库BatchLibrary 或如何包含批处理文件(缓存)
It creates each time a temporary batch file, combined of the own code and the library code.
It do some advanced functions at the library startup like secure parameter access.
But in my opinion it's also easy to use
它每次创建一个临时批处理文件,结合自己的代码和库代码。
它在库启动时执行一些高级功能,例如安全参数访问。但在我看来它也很容易使用
A user script sample
用户脚本示例
@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%
EDIT: Another way is ...
编辑:另一种方法是......
4) A macro library
4) 宏库
You could use batch-macros, it's easy to include and to use them.
您可以使用批处理宏,很容易包含和使用它们。
call MacroLib.bat
set myString=abcdef
%$strLen% result,myString
echo The length of myString is %result%
But it's tricky to build the macros!
More about the macro technic at Batch "macros" with arguments(cached)
但是构建宏很棘手!
更多关于带参数的批处理“宏”的宏技术(缓存)
MacroLibrary.bat
宏库.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=,
回答by Aacini
There is an easier way to load the library functions each time the main file is executed. For example:
每次执行主文件时,都有一种更简单的方法来加载库函数。例如:
@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
回答by cyberponk
I came up with a simple solution for using external libraries with batch files, and I would like to ask you guys to test it and find possible bugs.
我想出了一个使用带有批处理文件的外部库的简单解决方案,我想请你们测试它并找出可能的错误。
How to use:
如何使用:
- Create a library (a folder with library batch files inside)
- Put this header before any batch file you create that uses a library.
- 创建一个库(一个包含库批处理文件的文件夹)
- 将此标头放在您创建的使用库的任何批处理文件之前。
Principle of operation:
工作原理:
- Creates a temporary file with the libraries copied at the end of the file. It searches for the libraries in all paths listed in %_IncludesPath%.
- For it to work, the libraries have to be in a "funcion" structure. Example libraries can be found at: http://www.commandline.co.uk/lib/treeview/index.php?contents.php&../treeview/main.php
- 创建一个临时文件,在文件末尾复制库。它在 %_IncludesPath% 中列出的所有路径中搜索库。
- 为了使其工作,库必须处于“功能”结构中。示例库可以在以下位置找到:http: //www.commandline.co.uk/lib/treeview/index.php?contents.php&../treeview/ main.php
How it works:
这个怎么运作:
- Creates a temporary file at %TEMP% (won′t work if %TEMP% is not set)
- Copies itself to this temporary file
- Searches for each library in these paths:
- original batch file path
- %BatchLibraryPath%
- Any other path listed in %_IncludesPath%
- Appends these libraries to the temporary file
- Runs the temporary file
- exits and deletes temporary file
- 在 %TEMP% 创建一个临时文件(如果未设置 %TEMP% 将不起作用)
- 将自身复制到这个临时文件
- 在这些路径中搜索每个库:
- 原始批处理文件路径
- %BatchLibraryPath%
- %_IncludesPath% 中列出的任何其他路径
- 将这些库附加到临时文件
- 运行临时文件
- 退出并删除临时文件
Advantages:
好处:
- Passed command line arguments work perfectly
- No need to end the user code with any special command
- Libraries can be anywhere in the computer
- Libraries can be in shared folders with UNC paths
- You can have libraries in different paths and all of them will be added (if same library is found in different paths, the one at the left-most path in %_IncludesPath% is used)
- Returns errorlevel if any error occurs
- 传递的命令行参数工作完美
- 无需以任何特殊命令结束用户代码
- 库可以在计算机的任何位置
- 库可以位于具有 UNC 路径的共享文件夹中
- 您可以在不同的路径中拥有库,并且所有这些库都会被添加(如果在不同的路径中找到相同的库,则使用 %_IncludesPath% 中最左侧路径的那个)
- 如果发生任何错误,则返回错误级别
Code:
代码:
- Here is an example: for this to work you must have the Example.bat library in the Your_batch_file.bat folder (or in one of the %_IncludesPath% folders)
- 这是一个示例:为此,您必须在 Your_batch_file.bat 文件夹(或 %_IncludesPath% 文件夹之一)中有 Example.bat 库
Your_batch_file.bat
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
例子.bat
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Example msg
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEEXTENSIONS & set "msg=%1"
echo/%msg%
endlocal & goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
If you want an easy way to set the %BatchLibraryPath%, just put this file inside your Library path and run it before running Your_batch_file.bat. This setting is persistent on reboots, so you run this once only:
如果您想要一种简单的方法来设置 %BatchLibraryPath%,只需将此文件放在您的库路径中并在运行 Your_batch_file.bat 之前运行它。此设置在重新启动时保持不变,因此您只需运行一次:
SetBatchLibraryPath.bat
SetBatchLibraryPath.bat
setx BatchLibraryPath "%~dp0"
pause
回答by tekgypsy
okay... quick & dirty because I'm a UNIX guy... create your "library" file
好的...快速而肮脏,因为我是一个 UNIX 人...创建您的“库”文件
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>
this should be pretty straight-forward for you... at line 15 we make the jump to mainline to begin actual execution. At lines 19 and 27 we create entry points for our routines. At lines 35 and 36 are calls to the internal routines.
这对您来说应该是非常直接的……在第 15 行,我们跳转到主线以开始实际执行。在第 19 和 27 行,我们为例程创建入口点。第 35 和 36 行是对内部例程的调用。
now, you build the file that will call the library routines..
现在,您构建将调用库例程的文件..
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>
line 12 "imports" the "library"... actually it's just syntactic sugar that makes the subsequent calls easier...
第 12 行“导入”了“库”……实际上它只是使后续调用更容易的语法糖……
回答by Ioan Marin
I wrote a script to import subroutines into the main script.
我写了一个脚本将子程序导入到主脚本中。
The syntax is something like:
语法类似于:
if not defined _import (
rem OPTIONAL (before the "import" calls):
set "CMD_LIBRARY=<library_directory_path>"
import "[FILE_PATH1]filename1" / [DIR_PATH1]
...
import "[FILE_PATHn]filenamen" / [DIR_PATHn]
import end "%~0"
)
<MAIN SCRIPT CODE>
...
Please see this answer.
请看这个答案。
回答by user2882237
Another solution would be to temporary append the library functions to the running batch file.
The original file can be saved in a temporary file before the change and restored when finished.
This has the downside that you need to call the :deimport function at the end to restore the file and remove the temporary file. You also need to be able to write to the batch file and the folder you are currently in.
另一种解决方案是将库函数临时附加到正在运行的批处理文件中。
原始文件可以在更改前保存在临时文件中,并在完成后恢复。这有一个缺点,你需要在最后调用 :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
测试.bat
:test
ECHO output from test.bat
GOTO:EOF
C:\path with spaces\lib 2.bat
C:\带有空格的路径\lib 2.bat
:LIB2TEST
ECHO output from lib 2.bat
GOTO:EOF
Alternatively using the external version. Note this imports the deimport function so make sure you remove it in the demo.bat file.
或者使用外部版本。请注意,这会导入 deimport 函数,因此请确保在 demo.bat 文件中将其删除。
import.bat
导入.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