如何将参数传递给批处理

时间:2017-03-22 17:17:50

标签: batch-file parameters subroutine

如果我写

setlocal EnableDelayedExpansion
for /L %%a in (1,1,%NUMBER%) do (
    ECHO #define BLE_UUID_!SERVICE_NAME_UC!_!CARACTERISTIC_NAME_UC[%%a]!_CHAR   !CARACTERISTIC_UUID[%%a]!
)

NUMBER SERVICE_NAME_UC CARACTERISTIC_NAME_UC [%% a] CARACTERISTIC_UUID [%% a] 以前设置好了,一切正常,我得到了:

#define BLE_UUID_SECURITY_RELAY_CMD_CHAR        0x4800
#define BLE_UUID_SECURITY_RELAY_STATUS_CHAR     0x4801
#define BLE_UUID_SECURITY_CONFIG_CHAR   0x4802

但是,我想要做的是在执行任务的FOR循环中调用子例程,例如以这种方式:

setlocal EnableDelayedExpansion
for /L %%a in (1,1,%NUMBER%) do (
    CALL :SetOutput_h %INPUT_HEADER_PATH%\DefCharUUID.txt %%a
)

GOTO:EOF
:SetOutput_h
:: Subroutine to insert parts of code in the  header output file
:: The argument for this subroutine is the NAME of the code part you want to insert in the output file
SET "PART_NAME_H=%~1"
SET "INDEX=%~2"
(FOR /F "delims=" %%A IN ('findstr /N "^" %PART_NAME_H%') DO (

   REM Get the line *including* !variable! replacements
   SET "line=%%A"

   REM Remove leading number, show the rest *including* empty lines
   ECHO(!line:*:=!

)) >> %OUTPUT_H%
GOTO:EOF

文件 DefCharUUID.txt 只包含此内容:

#define BLE_UUID_!SERVICE_NAME_UC!_!CARACTERISTIC_NAME_UC[%INDEX%]!_CHAR    !CARACTERISTIC_UUID[%INDEX%]!

genarated输出文件包含:

#define BLE_UUID_SECURITY__CHAR

因此,方括号的部分已被忽略。

我做错了什么?

1 个答案:

答案 0 :(得分:0)

您的代码存在问题:

SET "line=%%A"

循环变量A具有字符串值:

#define BLE_UUID_!SERVICE_NAME_UC!_!CARACTERISTIC_NAME_UC[%INDEX%]!_CHAR    !CARACTERISTIC_UUID[%INDEX%]!

延迟扩展适用于将此字符串分配给环境变量line

%INDEX%的即时扩展不再进行了。 Windows命令解释器使用%VariableName%扩展了所有环境变量引用,已经解析了整个 FOR 命令块,从代码开始(FOR /F并以))结束命令 FOR 是第一次执行。

因此,在将从文件读取的行分配给环境变量!SERVICE_NAME_UC!时,SECURITY被字符串line替换。但Windows命令解释程序无法找到名为CARACTERISTIC_NAME_UC[%INDEX%]的环境变量和另一个名为CARACTERISTIC_UUID[%INDEX%]的环境变量,导致两个环境变量伪数组引用都被空字符串替换。

我不确定为什么你编写头文件创建这么复杂,但这里是你的问题的解决方案,其中包含额外的行minimal, complete, and verifiable example在批处理文件执行完成后不留任何文件。

@echo off
setlocal EnableExtensions
set "NUMBER=3"
set "SERVICE_NAME_UC=SECURITY"
set "CHARACTERISTIC_NAME_UC[1]=RELAY_CMD"
set "CHARACTERISTIC_NAME_UC[2]=RELAY_STATUS"
set "CHARACTERISTIC_NAME_UC[3]=CONFIG"
set "CHARACTERISTIC_UUID[1]=0x4800"
set "CHARACTERISTIC_UUID[2]=0x4801"
set "CHARACTERISTIC_UUID[3]=0x4802"
set "INPUT_HEADER_PATH=%TEMP%"
set "OUTPUT_H=%TEMP%\output.h"
del "%OUTPUT_H%" 2>nul
echo #define BLE_UUID_!SERVICE_NAME_UC!_!CHARACTERISTIC_NAME_UC[%%INDEX%%]!_CHAR    !CHARACTERISTIC_UUID[%%INDEX%%]!>"%INPUT_HEADER_PATH%\DefCharUUID.txt"

for /L %%I in (1,1,%NUMBER%) do (
    call :SetOutput_h "%INPUT_HEADER_PATH%\DefCharUUID.txt" %%I
)

type "%OUTPUT_H%"
del "%OUTPUT_H%"
del "%INPUT_HEADER_PATH%\DefCharUUID.txt"
endlocal
goto :EOF

:SetOutput_h
:: Subroutine to insert parts of code in the header output file.
:: The argument for this subroutine is the NAME of the code part you want to insert in the output file.
set "INDEX=%~2"
for /F "delims=" %%L in ('%SystemRoot%\System32\findstr.exe /N "^" "%~1"') do call :ExpandLine "%%L"
goto :EOF

:ExpandLine
set "Line=%~1"
call set "Line=%Line%"
setlocal EnableDelayedExpansion
set "Line=%Line%"
echo(!Line:*:=!>>"%OUTPUT_H%"
endlocal
goto :EOF

提供的解决方案将从文件读取的行传递给另一个子例程。传递的行首先分配给子例程Line中的环境变量ExpandLine

使用命令行扩展使用立即扩展的下一个环境变量:

call set "Line=%Line%"

在此命令行之后,环境变量Line首次运行主 FOR 时循环字符串值:

#define BLE_UUID_!SERVICE_NAME_UC!_!CHARACTERISTIC_NAME_UC[1]!_CHAR    !CHARACTERISTIC_UUID[1]!

现在启用了延迟扩展,并且在将两次扩展行打印到输出文件之前,使用额外的延迟扩展再次扩展此行。

我非常确定您真正想要实现的目标可以更加轻松,如下所示,它完全省略了文件[%INDEX%]中的DefCharUUID.txt

@echo off
setlocal EnableExtensions
set "NUMBER=3"
set "SERVICE_NAME_UC=SECURITY"
set "CHARACTERISTIC_NAME_UC[1]=RELAY_CMD"
set "CHARACTERISTIC_NAME_UC[2]=RELAY_STATUS"
set "CHARACTERISTIC_NAME_UC[3]=CONFIG"
set "CHARACTERISTIC_UUID[1]=0x4800"
set "CHARACTERISTIC_UUID[2]=0x4801"
set "CHARACTERISTIC_UUID[3]=0x4802"
set "INPUT_HEADER_PATH=%TEMP%"
set "OUTPUT_H=%TEMP%\output.h"
del "%OUTPUT_H%" 2>nul
echo #define BLE_UUID_!SERVICE_NAME_UC!_!CHARACTERISTIC_NAME_UC!_CHAR    !CHARACTERISTIC_UUID!>"%INPUT_HEADER_PATH%\DefCharUUID.txt"

setlocal EnableDelayedExpansion
for /L %%I in (1,1,%NUMBER%) do (
    set "CHARACTERISTIC_NAME_UC=!CHARACTERISTIC_NAME_UC[%%I]!"
    set "CHARACTERISTIC_UUID=!CHARACTERISTIC_UUID[%%I]!"
    for /F "delims=" %%L in ('%SystemRoot%\System32\findstr.exe /N "^" "%INPUT_HEADER_PATH%\DefCharUUID.txt"') do (
        set "Line=%%L"
        echo(!Line:*:=!>>"%OUTPUT_H%"
    )
)
endlocal

type "%OUTPUT_H%"
del "%OUTPUT_H%"
del "%INPUT_HEADER_PATH%\DefCharUUID.txt"
endlocal

更多提示:

GOTO 是命令,:EOF是参数。尽管Windows命令解释器在应用纠错后也处理GOTO:EOF,但不要将它们一起编写。

建议在批处理文件中引用其他脚本或应用程序(如 FINDSTR )以及完整路径和文件扩展名,以使批处理文件独立于本地环境变量PATHEXT的当前值和PATH尽可能多。

将所有文件/目录引用用双引号括起来,即使当前文件/目录名称/路径并不真正需要,因为将来真正了解文件/目录名称/路径。