【问题标题】:Batch File Math (Subtraction) Stopped Working批处理文件数学(减法)停止工作
【发布时间】:2018-08-14 16:02:07
【问题描述】:

我知道这肯定有一些语法问题,但我现在无法解决这个问题。这是我几个月前整理的一个脚本,用于在每个月发布时自动为我下载一些文件。它工作正常,但是这个月我注意到没有下载任何东西。经过一些故障排除和调查,我发现月份变量将自己设置为“-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

这是我保存下载尝试日志的地方 回显日期 > %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”而不是实际执行减法,我基本上是在拔头发试图弄清楚我在做什么我做错了。

【问题讨论】:

    标签: batch-file math cmd subtraction


    【解决方案1】:

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

    0809octal numeral system 中的无效数字,因此函数 strtol 返回 0,然后再减去 1,得到 -1

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

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

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

    第一行将0-11 连接到00-011,第二行只取该字符串的最后两个字符,从而将00-11 最终分配给环境变量@ 987654348@.

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

    【讨论】:

    • 我认为这是一个很好的起点,谢谢。我不认为 0X 与 X 是一个算法问题。由于正在下载的文件的文件名约定,我将其格式化为 0X,但我当然可以做更多的工作来根据需要来回更改数字格式。我会试一试并发布我的结果,非常感谢:-)
    • 看起来它正在工作,所以我这样做了:set mm=1%mm%set /a "mm=mm-101" 一开始,我有一长串将格式恢复为 0X 的清单当我们到达 27 日一天,它正在这样做:if %dd%==27 (set mm=1%mm%set /a "mm=mm-101")
      总的来说,只需多写两行代码,我就可以停止拉扯我的头发了。再次感谢您!
    猜你喜欢
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多