批处理文件数学(减法)停止工作

Batch File Math (Subtraction) Stopped Working

我知道我这边肯定有一些语法问题,但我现在无法解决这个问题。这是我几个月前整理的一个脚本,可以在每月发布时自动为我下载一些文件。它工作正常,但是这个月我注意到没有任何下载。经过一些故障排除和调查,我发现月份变量将其自身设置为“-1”,而不是从其当前值中减去“1”。因此,我无法获得正确的文件名来尝试下载。这与我在天数、修订号和年份上使用的匹配相同,但出于某种原因,月份变量与我不合作,我不明白为什么。

    :MASTER
        @echo off
        mode con:cols=100 lines=5
    ::Setup First Download
        for /f "tokens=2*" %%a in ('REG Query "HKLM\SOFTWARE\Wow6432Node\ExampleRegistryKey" /v ExampleString 2^>nul') do set "ExampleDir=%%~b"
        pushd "%ExampleDir%"
        for /f "tokens=2 delims==" %%a in ('findstr SQLiteHome Example.ini') do set SQLiteHome=%%a
        ::Revision Number
        set num=17
        set /a "num=num-1"
        ::Begin set date
        for /f "tokens=1-4 delims=/-. " %%i in ('date /t') do (call :set_date %%i %%j %%k %%l)
        goto :end_set_date
        :set_date
        if "%1:~0,1%" gtr "9" shift
        for /f "skip=1 tokens=2-4 delims=(-)" %%m in ('echo,^|date') do (set %%m=%1&set %%n=%2&set %%o=%3)
        goto :eof
        :end_set_date
        set dd=31

这里的这一部分是月份开始等于 -1 而不是从当前月份减去当前月份的地方。

        set /a "mm=mm-1"
        if %mm%==9 set mm=09
        if %mm%==8 set mm=08
        if %mm%==7 set mm=07
        if %mm%==6 set mm=06
        if %mm%==5 set mm=05
        if %mm%==4 set mm=04
        if %mm%==3 set mm=03
        if %mm%==2 set mm=02
        if %mm%==1 set mm=01
        if %mm%==0 set /a "yy=yy-1"
        if %mm%==0 set mm=12
        Set EarlyEntry=early_up_sqlite_r
        Set FullEntry=update_sqlite_r
        Set MstarEntry=mstar_ext_sqlite_r
        Set PSNEntry=psn_ext_sqlite_r
        set CurrentEntry=%EarlyEntry%
        set ThisFile=%CurrentEntry%%num%_%yy%%mm%%dd%.exe
        ECHO %ThisFile%
        set INIentry=EarlyLast
    ::Create %WorkingDirectory%\Dates.txt and Downloads.ini
        set INIfile=C:\ProgramData\SA_Updater\Downloads.ini
        set WorkingDirectory=C:\ProgramData\SA_Updater\
        set OldDownloads=C:\ProgramData\SA_Updater\Downloads\
        set PSNini=PSNLast
        set MSTARini=MSTARLast
        set Fullini=FullLast
        set Earlyini=EarlyLast
        echo %PSNini%
        echo Dates > %WorkingDirectory%\Dates.txt
        if not exist "%WorkingDirectory%" mkdir "%WorkingDirectory%"
        if not exist "%OldDownloads%" mkdir "%OldDownloads%"
        pusd %WorkingDirectory%
        if not exist "%INIfile%" (
        ECHO %PSNini%= > %INIfile%
        ECHO %MSTARini%= >> %INIfile%
        ECHO %Fullini%= >> %INIfile%
        ECHO %Earlyini%= >> %INIfile%
        )
    :ObtainVariables
        ::Find the Last version downloaded

这是我保存下载尝试日志的地方 echo 日期 > %WorkingDirectory%\Dates.txt 输出看起来像这样:

Dates 

http://Example.com/updates/early_up_sqlite_r16_2018-131.exe 
http://Example.com/updates/early_up_sqlite_r15_2018-131.exe 
http://Example.com/updates/early_up_sqlite_r14_2018-131.exe 

而不是:

Dates 

http://Example.com/updates/early_up_sqlite_r16_20180731.exe 
http://Example.com/updates/early_up_sqlite_r15_20180731.exe 
http://Example.com/updates/early_up_sqlite_r14_20180731.exe

脚本的其余部分:

            for /f "tokens=2 delims==" %%a in ('findstr %INIentry% %INIfile%') do set LastINIfile=%%a
            ECHO %LastINIfile%
        ::Revision Number
            set num=17
            set /a "num=num-1"
        ::Begin set date
            for /f "tokens=1-4 delims=/-. " %%i in ('date /t') do (call :set_date %%i %%j %%k %%l)
            goto :end_set_date
            :set_date
            if "%1:~0,1%" gtr "9" shift
            for /f "skip=1 tokens=2-4 delims=(-)" %%m in ('echo,^|date') do (set %%m=%1&set %%n=%2&set %%o=%3)
            goto :eof
            :end_set_date
            set dd=31
            set /a "mm=mm-1"
            if %mm%==9 set mm=09
            if %mm%==8 set mm=08
            if %mm%==7 set mm=07
            if %mm%==6 set mm=06
            if %mm%==5 set mm=05
            if %mm%==4 set mm=04
            if %mm%==3 set mm=03
            if %mm%==2 set mm=02
            if %mm%==1 set mm=01
            if %mm%==0 set /a "yy=yy-1"
            if %mm%==0 set mm=12
            set ThisFile=%CurrentEntry%%num%_%yy%%mm%%dd%.exe
            goto Download
    :Download
        ::Setup Download Variables
            cls
            set Download=http://Example.com/updates/%ThisFile%
            GOTO TryDownload
    :TryDownload
        ::Add Download Attempt to %WorkingDirectory%\Dates.txt
            echo %Download% >> %WorkingDirectory%\Dates.txt
        ::Is the file download? If so, start the install
            cls
            mode con:cols=100 lines=10
            powershell "Import-Module BitsTransfer; Start-BitsTransfer '%Download%' '%DownloadDir%'"
            mode con:cols=100 lines=5
            cls
            ::ping localhost -n 3 >nul
            if exist C:\ProgramData\SA_Updater\%ThisFile% (
            GOTO StartInstall
            ) else (
        ::Try Downloading
            GOTO TryAgain
            )
            cls
    :TryAgain
        set /a "num=num-1"
        if %mm%==9 set mm=09
        if %mm%==8 set mm=08
        if %mm%==7 set mm=07
        if %mm%==6 set mm=06
        if %mm%==5 set mm=05
        if %mm%==4 set mm=04
        if %mm%==3 set mm=03
        if %mm%==2 set mm=02
        if %mm%==1 set mm=01
        if %num%==0 set /a "dd=dd-1"
        if %dd%==27 set /a "mm=mm-1"
        if %mm%==0 set /a "yy=yy-1"
        if %mm%==0 set mm=12
        if %dd%==27 set dd=33
        if %num%==0 set num=17
        set ThisFile=%CurrentEntry%%num%_%yy%%mm%%dd%.exe
        set Download=http://Example.com/updates/%ThisFile%
        set DownloadDir=%WorkingDirectory%%ThisFile%
        if %ThisFile% EQU %LastINIfile% GOTO CheckEarly
        GOTO TryDownload
        )
    :StartInstall
        %WorkingDirectory%%ThisFile% /w /v"INSTALLPREREQUISITES=0"
        robocopy %WorkingDirectory% %OldDownloads% %ThisFile%
        pushd %WorkingDirectory%
        del %ThisFile%
        del /Q /A H *.tmp
        GOTO DoINIstuff
    ::Update ThisFile
        :CheckEarly
            if %CurrentEntry% EQU %EarlyEntry% GOTO SetupFull
            GOTO CheckFull
        :CheckFull
            if %CurrentEntry% EQU %FullEntry% GOTO SetupMstar
            GOTO CheckMstar
        :CheckMstar
            if %CurrentEntry% EQU %MstarEntry% GOTO SetupPSN
            GOTO CheckPSN
        :CheckPSN
            if %CurrentEntry% EQU %PSNEntry% GOTO SetupEarly
            GOTO CheckEarly
    ::Setups
        :SetupFull
            set CurrentEntry=%FullEntry%
            set INIentry=%Fullini%
            GOTO ObtainVariables
        :SetupMstar
            set CurrentEntry=%MstarEntry%
            set INIentry=%MSTARini%
            GOTO ObtainVariables
        :SetupPSN
            set CurrentEntry=%PSNEntry%
            set INIentry=%PSNini%
            GOTO ObtainVariables
        :SetupEarly
            set CurrentEntry=%EarlyEntry%
            set INIentry=%Earlyini%
            GOTO ObtainVariables
    :DoINIstuff
        SetLocal EnableDelayedExpansion
        Set _PathtoFile=%INIfile%
        Set _OldLine=%INIentry%=
        Set _NewLine=%INIentry%=%ThisFile%
        Call :_Parse "%_PathtoFile%"
        Set _Len=0
        Set _Str=%_OldLine%
        Set _Str=%_Str:"=.%987654321
        :_Loop
        If NOT "%_Str:~18%"=="" Set _Str=%_Str:~9%& Set /A _Len+=9& Goto _Loop
        Set _Num=%_Str:~9,1%
        Set /A _Len=_Len+_Num
        PushD %_FilePath%
        If Exist %_FileName%.new Del %_FileName%.new
        If Exist %_FileName%.old Del %_FileName%.old
        Set _LineNo=0
        For /F "Tokens=* Eol=" %%I In (%_FileName%%_FileExt%) Do (
        Set _tmp=%%I
        Set /A _LineNo+=1
        If /I "!_tmp:~0,%_Len%!"=="%_OldLine%" (
        >>%_FileName%.new Echo %_NewLine%
        ) Else (
        If !_LineNo! GTR 1 If "!_tmp:~0,1!"=="[" Echo.>>%_FileName%.new
        SetLocal DisableDelayedExpansion
        >>%_FileName%.new Echo %%I
        EndLocal
        ))
        Ren %_FileName%%_FileExt% %_FileName%.old
        Ren %_FileName%.new %_FileName%.ini
        PopD
        Goto :CheckEarly
        :_Parse
        Set _FilePath=%~dp1
        Set _FileName=%~n1
        Set _FileExt=%~x1
        Goto :EOF

我希望我没有遗漏太多来解决这个问题。基本上,我可以看到修订号和日期按它们应有的方式运行,但是月份只是恢复为“-1”而不是实际执行减法,我基本上是在竭尽全力想弄清楚我的意思我做错了。

原因很简单。带有前导 0 的数字字符串被 C 函数 strtol 解释为八进制数,cmd.exe 使用该函数将数字字符串转换为整数。

0809octal numeral system 中的无效数字,因此函数 strtol returns 0 接下来减去1 导致 -1.

简单的解决方案是使用 set /a "mm=1%mm%-101" 而不是 set /a "mm=mm-1"。然后首先将月份值作为字符串与字符 1 连接起来,构建字符串 101112,因此数字字符串不再有前导 0 并且从这个数字 101 被减去得到 011 作为字符串分配给环境变量 mm.

顺便说一句:使用以下两个命令行来取回减法后的前导零:

set "mm=0%mm%"
set "mm=%mm:~-2%"

第一行将 0-11 连接到 00-011,第二行仅采用该字符串的最后两个字符,结果为 00-11最终赋值给环境变量mm.

接下来的两行应替换为:if %mm% == 00 set "mm=12" & set /a "yy-=1"