首页 文章

紧接着再次运行批处理脚本时出错

提问于
浏览
0

我正在为我班上的第6个作业编写一个批处理脚本,当我完成时我遇到了麻烦 . (我们通常专注于bash脚本,所以我是批处理的新手)

脚本在第一次运行时根据需要运行;但第二次运行它时表现不同 .

本质上,脚本检查参数的值(如果存在)并根据值运行特定代码 . 例如,如果参数为“1”,则它检查PATH变量以查找目录,如果它不存在则创建它,如果它存在 - 没有任何反应,它只是继续脚本 .

修改PATH后第二次运行脚本时会出现此问题 . 我收到输出“\普通在这个时候没有预料到” .

我第一次运行脚本时遇到了类似的问题,但设法通过在IF语句的评估两侧包含引号来修复它,但现在我不确定在哪里继续这个 .

我的代码如下:

@echo on

IF "%1%" == "0" (
    SET "VAR1=%path%"
    echo.%VAR1%|findstr /C:"App0" >nul 2>&1
    if errorlevel 1 SET "PATH=%PATH%%cd%\App0;"
    if not errorlevel 1 echo Found
    goto errorBypass
) ELSE IF "%1%" == "1" (
    SET "VAR2=%path%"
    ECHO %VAR2%
    echo.%VAR2%|findstr /C:"App1" >nul 2>&1
    if errorlevel 1 SET "PATH=%PATH%%cd%\App1;"
    if not errorlevel 1 echo Found
    goto errorBypass
) ELSE IF "%1%" == "" (
    IF "%HUMBER_HOME%" == "" (
        goto Error2
    ) ELSE (
        CALL "HUMBER_HOME\bin\setEnv.bat"
        goto errorBypass
    )
)
echo HERE

:Error2
echo Error2

:errorBypass
call "run.bat"

另外,所以我知道将来参考 - 有没有一种有效的方法来逐行调试?或者可以输出发生错误的特定行的命令?当一个错误可能由不同地方的多个问题引起时,我发现有点困难 .

1 回答

  • 1

    引用批处理文件参数

    打开命令提示符窗口并运行 call /? . 输出帮助解释了如何引用批处理文件参数 . %1 引用传递给批处理文件的第一个参数 . 这可以是例如 1 (未引用参数字符串),但也可以是 "1" (引用参数字符串) . %~1 引用第一个参数字符串,其中包含周围的双引号 .

    在参数引用之后再添加一个 % 是错误的 . 语法 %variable% 用于引用环境变量的字符串值 . 批处理文件参数仅使用百分号和数字引用,不带或带有修饰符 . 数字后面没有百分号 . 这也是 123 ,...无法作为环境变量名称的原因 .

    所以不好 IF "%1%" == "0" ( 因为这会导致批处理文件调用 "1" 作为执行命令行的第一个参数:

    IF ""1"" == "0" (
    

    更好的语法是 IF "%~1" == "0" ( ,这导致执行命令行:

    IF "1" == "0" (
    

    有关如何评估批处理文件参数的更多详细信息,请参阅difference between “…” and x“…” in batch上的答案 .

    将文件夹路径附加到本地PATH

    环境变量 PATH 包含comma-separated list个文件夹路径,其中列表分隔符是分号而不是逗号 .

    因此 PATH 末尾的 ; 表示还有一个文件夹路径是空文件夹路径 . 可以在 PATH 的中间或末尾指定空文件夹路径,但这样做是不好的做法,因为 PATH 不应包含空文件夹路径 .

    因此,代码中的以下命令行不好:

    if errorlevel 1 SET "PATH=%PATH%%cd%\App0;"
    

    如果 PATH 尚未以分号结尾,那么也会丢失 ; ,这可能是第二次执行批处理文件时出现错误消息的原因 .

    完整修订的批处理文件代码可以在下面看到更好的代码 .

    引用当前目录

    可以使用 %CD% 引用当前目录,该目录可能与 %~dp0 引用的批处理文件目录不同 . %~dp0 引用参数0的驱动器和路径,它是批处理文件本身 . 以 %~dp0 引用的批处理文件路径字符串始终以反斜杠结尾 . 因此,在将 %~dp0 与文件/文件夹名称连接后,不应使用额外的反斜杠 .

    动态环境变量 CD 通常在结束时没有反斜杠结束 . 因此,在大多数情况下, %CD% 必须与带有文件/文件夹名称的附加 \ 连接 . 但是在批处理文件中使用 %CD% 时必须考虑一个例外: %CD% 扩展为当前目录末尾为 \ 的字符串,即驱动器的根目录,例如 C:\D:\ . 因此,在使用 %CD% 来检查字符串是否已经以反斜杠结尾之前,在添加文件/文件夹名称之前或者使用额外的反斜杠时,始终是必要的 .

    其他建议

    在使用在命令块中定义/修改并在命令块中引用的环境变量时,应避免使用以 ( 开头并以 ) 结尾的命令块,因为这需要使用delayed expansion,如帮助输出所解释的那样运行 set /? IF 上的命令提示符窗口和 FOR 示例,通常使用命令块 . Windows命令处理器主要用于执行另一个命令行 . 命令块的使用可以加速某些批处理文件的执行案件,但在许多情况下,最好避免它们 .

    有关如何调试批处理文件的简短说明,请参见debugging a batch file . 单步执行实际上是不可能的 . 但 cmd.exe 显示在哪个行或命令块上发生错误导致退出批处理文件执行以及错误是什么 .

    修改了批处理文件代码

    这是修改后的批处理文件代码:

    @echo off
    goto Main
    
    :AddPath
    echo %PATH%;|%SystemRoot%\System32\findstr.exe /I /C:"\%~1;" >nul 2>&1
    if not errorlevel 1 echo Found %~1 in PATH& goto :EOF
    set "Separator=;"
    if "%PATH:~-1%" == ";" set "Separator="
    if "%CD:~-1%" == "\" (set "AppPath=%CD%%~1") else set "AppPath=%CD%\%~1"
    set "PATH=%PATH%%Separator%%AppPath%"
    set "AppPath="
    set "Separator="
    goto :EOF
    
    :Main
    if "%~1" == "0" call :AddPath App0 & goto errorBypass
    if "%~1" == "1" call :AddPath App1 & goto errorBypass
    if not "%~1" == "" goto RunApp
    if "%HUMBER_HOME%" == "" goto Error2
    if exist "%HUMBER_HOME%\bin\setEnv.bat" (
        call "%HUMBER_HOME%\bin\setEnv.bat"
        goto errorBypass
    )
    
    echo File "setEnv.bat" in subdirectory "bin" in directory
    echo defined by environment variable HUMBER_HOME not found.
    echo HUMBER_HOME directory: "%HUMBER_HOME%"
    echo/
    pause
    goto :EOF
    
    
    :RunApp
    echo HERE
    goto :EOF
    
    :Error2
    echo Error2
    goto :EOF
    
    :errorBypass
    if exist "run.bat" call "run.bat"
    

    在批处理文件的顶部定义了子程序 AddPath ,这有点不寻常 . 所以带有 goto Main 的第二行导致在开始执行批处理文件时跳过子程序的代码 .

    在第一个参数为 0"0"1"1" 时,使用 App0App1 调用子程序 AddPath .

    AddPath 中的第一行输出本地环境变量 PATH 的当前值,并附加分号,并将此输出重定向到 FINDSTR ,它搜索不区分大小写的字面上的字符串,用于反斜杠后以分号结尾传递给子例程的第一个参数字符串 . 额外的 \; 应该避免 PATH 中任何文件夹路径中的误报,也可以在文件夹路径中间某处包含 App0App1 . 这个小小的增强不是100%安全的,但应该足够好 .

    FINDSTR 在行中找到的搜索字符串上以 0 退出 . 在这种情况下,只输出一条信息消息并退出子程序,这导致在之前调用子程序的主代码上继续执行批处理文件 . 否则,必须将传递的应用程序名称添加到本地 PATH .

    也可以看看:

    首先,环境变量 Separator 定义为 ; 作为值 . 但是,如果本地 PATH 已经以反斜杠结束,但它不应该,则立即删除环境变量 . 请注意,如果 PATH" 结尾,则将 PATH 的最后一个字符与 ; 进行比较的命令行可能会失败 . 所以这个简单的版本不是100%安全的 .

    接下来,当前目录路径与传递的应用程序文件夹名称连接,不带或带有额外的反斜杠,具体取决于当前目录是驱动器的根目录或任何目录的子目录 .

    然后扩展本地 PATH ,根据传递的参数附加应用程序路径,之前没有或附加分号 .

    最后,在退出子例程之前,不再需要的环境变量 SeparatorAppPath 被删除 .

    发布的主要代码中的主要错误是在分配给环境变量 HUMBER_HOME 的目录的子目录 bin 中调用批处理文件 setEnv.bat 时,环境变量 HUMBER_HOME 周围缺少百分号 . 这可能是第二次执行批处理文件时出现错误消息的另一个原因 .

    修改后的代码首先在调用之前检查每个要调用的批处理文件是否确实存在 .

    要了解使用的命令及其工作方式,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面 .

    • call /?

    • echo /?

    • findstr /?

    • goto /?

    • if /?

    • pause /?

    • set /?

相关问题