如何正确地批量检查参数是否存在?

How to correctly check the presence of parameters in batch?

我现在尝试对一个简单的网络脚本进行批处理 3 个小时,但我一直在检查参数。

我实际用

IF not "%~1"=="" ( IF not "%~2"=="" (
    Set NHS_Network1 = %1
    Set NHS_Router1  = %2
))

执行时仍然出现语法错误。

这是我已经尝试过的:

所以...我现在很困惑。我从未批量做过 "complex" 事情,但我熟悉 bash、C、C++、Java、...

完整代码可能有一些错误,因为我卡在了开头。

REM #Configuration#
Set NHS_Network1 = 192.168.0.0/24
Set NHS_Router1  = 192.168.0.254
Set NHS_Network2 = 192.168.1.0/24
Set NHS_Router2  = 192.168.1.1
Set NHS_Gateway1 = 192.168.1.1
Set NHS_Gateway2 = 192.168.0.254

Echo Network Home Script V0.1
IF not "%~1"=="" ( IF not "%~2"=="" (
    Echo Overwriting Configuration
    REM  #Reset#
    Set NHS_Network1 = []
    Set NHS_Router1  = []
    Set NHS_Network2 = []
    Set NHS_Router2  = []
    Set NHS_Gateway1 = []
    Set NHS_Gateway2 = []
    REM #Variable setup#
    Set NHS_Network1 = %1
    Set NHS_Router1  = %2
))
IF not "%~3"=="" ( IF not "%~4"=="" (
    Set NHS_Network2 = %3
    Set NHS_Router2  = %4
))
IF not "%~5"==""(
    Set NHS_Gateway1 = %5
)
IF not "%~6"=="" (
    Set NHS_Gateway2 = %6
)

IF DEFINED %NHS_Network1% ( IF DEFINED %NHS_Router1% (
route delete %NHS_Network1%
route add %NHS_Network1% %NHS_Router1%
IF %ERRORLEVEL% NEQ 0 (Echo ERROR : Impossible to add the route, please check route print) else (Echo Route Add)
))

IF DEFINED %NHS_Network2% ( IF DEFINED %NHS_Router2% (
route delete %NHS_Network2%
route add %NHS_Network2% %NHS_Router2%
IF %ERRORLEVEL% NEQ 0 (Echo ERROR : Impossible to add the route, please check route print) else (Echo Route Add)
))

IF DEFINED %NHS_Gateway1% (
route delete 0.0.0.0/0
route add 0.0.0.0/0 %NHS_Gateway1% metric 10
IF %ERRORLEVEL% NEQ 0 (Echo ERROR : Impossible to add the route, please check route print) else (Echo Route Add)
)

IF DEFINED %NHS_Gateway2% (
route add 0.0.0.0/0 %NHS_Gateway2% metric 20
IF %ERRORLEVEL% NEQ 0 (Echo ERROR : Impossible to add the route, please check route print) else (Echo Route Add)
)

请阅读 Why is no string output with 'echo %var%' after using 'set var = text' on command line? 上的答案以了解为什么在批处理文件中将 1 个或多个 space 放在等号周围以将字符串分配给环境变量。

并阅读 this answer 解释批处理文件中 IF 条件的正确语法。在批处理文件中必须小心使用空格。在某些位置上需要 space,在其他位置上 space 通常是错误的。

并且必须注意在使用 ( ... ) 定义的块中引用环境变量的值,因为命令处理器使用 %variable% 替换对环境变量的所有引用在处理块中的行之前,通过它们在整个块中的值来语法。对于在块内定义或设置并在块内求值的环境变量,有必要启用延迟扩展并使用 !variable! 引用这些变量以使用延迟扩展。更好的是避免延迟环境变量扩展的需要。

goto 是 C/C++ 中很少使用的关键字。但在批处理文件中,它是一个非常重要的命令,它的使用使大多数批处理文件比使用 C/C++ 中使用的嵌套 IF 结构要容易得多,以避免使用 转到.

评估批处理文件的参数有一个通用规则:

如果没有定义第一个参数,则肯定没有更多的参数。

嗯,可以使用例如 "" "second parameter" ThirdParameter 调用批处理文件 运行 它带有 3 个参数,其中第一个是空字符串。但是对于您的脚本,可以将空字符串解释为根本未指定参数。

这是使用 goto 重新编码的批处理文件,避免了延迟扩展的需要。

@echo off
echo Network Home Script V0.1
setlocal

rem Default configuration

set "NHS_Network1=192.168.0.0/24"
set "NHS_Router1=192.168.0.254"
set "NHS_Network2=192.168.1.0/24"
set "NHS_Router2=192.168.1.1"
set "NHS_Gateway1=192.168.1.1"
set "NHS_Gateway2=192.168.0.254"

rem Run script with the defaults if executed without any
rem parameter or with just 1 parameter for first network.

if "%~1"=="" goto SetRoutes
if "%~2"=="" goto SetRoutes

rem IPv4 address with netmask and router address defined for network 1.

set "NHS_Network1=%~1"
set "NHS_Router1=%~2"

rem Delete all other by default defined environment variables.

set "NHS_Network2="
set "NHS_Router2="
set "NHS_Gateway1="
set "NHS_Gateway2="

if "%~3"=="" goto SetRoutes
if "%~4"=="" goto SetRoutes

rem IPv4 address with netmask and router address defined for network 2.

set "NHS_Network2=%~3"
set "NHS_Router2=%~4"

rem Set the gateway addresses if defined as fifth and sixth parameter.

if not "%~5"=="" set "NHS_Gateway1=%~5"
if not "%~6"=="" set "NHS_Gateway2=%~6"

:SetRoutes

rem The variables NHS_Network1 and NHS_Router1 are always defined.

%SystemRoot%\System32\route.exe delete %NHS_Network1%
%SystemRoot%\System32\route.exe add %NHS_Network1% %NHS_Router1%
if errorlevel 1 (
    echo ERROR : Impossible to add route for network 1, please check route print.
) else (
    echo Route for network 1 added.
)

rem NHS_Router2 is always defined if NHS_Network2 is defined.

if defined NHS_Network2 (
    %SystemRoot%\System32\route.exe delete %NHS_Network2%
    %SystemRoot%\System32\route.exe add %NHS_Network2% %NHS_Router2%
    if errorlevel 1 (
        echo ERROR : Impossible to add route for network 2, please check route print.
    ) else (
        echo Route for network 2 added.
    )
)

if defined NHS_Gateway1 (
    %SystemRoot%\System32\route.exe delete 0.0.0.0/0
    %SystemRoot%\System32\route.exe add 0.0.0.0/0 %NHS_Gateway1% metric 10
    if errorlevel 1 (
        echo ERROR : Impossible to add route for gateway 1, please check route print.
    ) else (
        echo Route for gateway 1 added.
    )
)

if defined NHS_Gateway2 (
    %SystemRoot%\System32\route.exe add 0.0.0.0/0 %NHS_Gateway2% metric 20
    if errorlevel 1 (
        echo ERROR : Impossible to add route for gateway 2, please check route print.
    ) else (
        echo Route for gateway 2 added.
    )
)

endlocal

另请参阅 Microsoft 支持文章 Testing for a Specific Error Level in Batch Files

if errorlevel 1 的用法 - 意味着如果先前命令或应用程序的退出代码大于或等于 1 - 优于在块中使用 %ERRORLEVEL% 作为命令处理器替换 %ERRORLEVEL%在完全执行上面的行之前,已经根据此变量的当前值解析块。如果不使用特殊语法来检查错误级别,则有必要使用延迟扩展。

要了解使用的命令及其工作原理,请打开命令提示符 window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • echo /?
  • endlocal /?
  • if /?
  • rem /?
  • route /?
  • set /?
  • setlocal /?
@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
SET args=%*
FOR %%a IN (NHS_Network1:192.168.0.0/24
NHS_Router1:192.168.0.254
NHS_Network2:192.168.1.0/24
NHS_Router2:192.168.1.1
NHS_Gateway1:192.168.1.1
NHS_Gateway2:192.168.0.254
) DO FOR /f "tokens=1,2delims=:" %%v IN ("%%a") DO (
 FOR /f "tokens=1*" %%t IN ('echo !args!') DO (
  IF "%%~t"=="" (SET "%%v=%%w") ELSE (SET "%%v=%%~t")
  IF DEFINED args (SET "args=%%u") ELSE (SET "%%v=%%w")
 )
)

SET nhs


GOTO :EOF

如果需要,可以添加其他数据 - 格式应该是显而易见的。

args 设置为提供给批处理的参数列表。

对于每个 varname:varvalue,将 %%v 分配给变量名并 %%w 默认值。

将变量设置为第一个剩余参数或默认值

如果还有剩余参数,请删除一个。否则,使用默认值。

与原版不完全相同,但可能有用。