Windows .bat / .cmd函数库在自己的文件中?

问题描述 投票:13回答:5

在DOS .bat / .cmd脚本中有a nice way to build functions。要模块化一些安装脚本,最好将带有函数库的文件包含到.bat / .cmd脚本中。

我试过的是:

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然后我得到以下输出:跳转目标 - 找不到function1。

或多或少意味着什么:找不到名为function1的跳转点

任何想法,或者这是不可能的?

windows function batch-file
5个回答
12
投票

这是可能的,并且有一些不同的方法可以做到这一点。

1)将完整的“库”复制并粘贴到每个文件中Works,但它实际上不是库,并且更改/更正所有文件中的库函数是一件恐怖事

2)通过call-wrapper包含一个库

call batchLib.bat :length result "abcdef"

和batchLib.bat以。开头

call %* 
exit /b
...
:length
...

易于编程,但速度很慢,因为每个库调用都会加载库批次,以及参数可能出现的问题。

3)一个“自装”库BatchLibrary or how to include batch files (cached)

它每次创建一个临时批处理文件,结合自己的代码和库代码。 它在库启动时执行一些高级功能,如安全参数访问。但在我看来,它也很容易使用

用户脚本示例

@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%

但是构建宏很棘手! 更多关于Batch "macros" with arguments (cached)的宏观技术

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=,

1
投票

每次执行主文件时都有一种更简单的方法来加载库函数。例如:

@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

1
投票

我想出了一个简单的解决方案,使用外部库和批处理文件,我想请你们测试它并找到可能的错误。

如何使用:

  • 创建一个库(里面有库批处理文件的文件夹)
  • 将此标头放在您创建的使用库的任何批处理文件之前。

工作原理:

这个怎么运作:

  • 在%TEMP%处创建临时文件(如果未设置%TEMP%,则不起作用)
  • 将自身复制到此临时文件
  • 在这些路径中搜索每个库: 原始批处理文件路径 %BatchLibraryPath% %_IncludesPath%中列出的任何其他路径
  • 将这些库附加到临时文件
  • 运行临时文件
  • 退出并删除临时文件

好处:

  • 传递的命令行参数完美运行
  • 无需使用任何特殊命令结束用户代码
  • 库可以在计算机的任何位置
  • 库可以位于具有UNC路径的共享文件夹中
  • 您可以在不同的路径中放置库,并且将添加所有库(如果在不同的路径中找到相同的库,则使用%_IncludesPath%中最左侧路径的库)
  • 如果发生任何错误,则返回errorlevel

码:

  • 下面是一个示例:要使其工作,您必须在Your_batch_file.bat文件夹中(或在%_IncludesPath%文件夹之一中)具有Example.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

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Example msg
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEEXTENSIONS & set "msg=%1"
  echo/%msg%
endlocal & goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

如果您想要一种简单的方法来设置%BatchLibraryPath%,只需将此文件放在Library路径中并在运行Your_batch_file.bat之前运行它。此设置在重新启动时是持久的,因此您只运行一次:

SetBatchLibraryPath.bat

setx BatchLibraryPath "%~dp0"
pause

0
投票

另一种解决方案是将库函数临时附加到正在运行的批处理文件。 原始文件可以在更改之前保存在临时文件中,并在完成后恢复。这有一个缺点,你需要在最后调用: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:\ path with spaces \ 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

0
投票

好吧...快速和脏,因为我是一个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 ^&lt;HTML^&gt;<br>
 21     ECHO ^&lt;HEAD^&gt;<br>
 22     ECHO    ^&lt;TITLE^&gt;%1^&lt;/TITLE^&gt;<br>
 23     ECHO ^&lt;/HEAD^&gt;<br>
 24     ECHO ^&lt;BODY^&gt;<br>
 25     GOTO :EOF<br>
 26 <br>
 27 :TRAILER<br>
 28     ECHO ^&lt;/BODY^&gt;<br>
 29     ECHO ^&lt;/HTML^&gt;<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行,我们跳转到主线开始实际执行。在第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行“导入”“库”...实际上它只是语法糖,使后续调用更容易......

© www.soinside.com 2019 - 2024. All rights reserved.