小编典典

具有常量的变量的批处理文件比较失败

go

我想编写一段简单的代码来获取一些格式良好的“时间戳”。将时间花在我的两个变量上Start,End效果很好。我也可以将其打印为0:0:0。我想要一个小于零的前导零,但是很显然我得到一个错误,说“未找到或错误键入参数10”。我发现这似乎是要比较的变量,但未能解决。有任何想法吗?

@ECHO OFF
REM Time Calculation
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Second /Format:table ^| findstr /r "."') DO (
 set Day=%%A
 set Hour=%%B
 set Minute=%%C
 set Second=%%D
)
set /a Start=%Day%*8640000+%Hour%*360000+%Minute%*6000+%Second%*100
@ECHO ON
ping 8.8.8.8 -n 11
@ECHO OFF
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Second /Format:table ^| findstr /r "."') DO (
 set Day=%%A
 set Hour=%%B
 set Minute=%%C
 set Second=%%D
)
set /a End=%Day%*8640000+%Hour%*360000+%Minute%*6000+%Second%*100
set /a Diff=%End%-%Start%
set /a Diff=(%Diff%)/100
set /a DiffSec=%Diff%%%60
set /a Diff=(%Diff%-%Diff%%%60)/60
set /a DiffMin=%Diff%%%60
set /a Diff=(%Diff%-%Diff%%%60)/60
set /a DiffHrs=%Diff%

ECHO Laufzeit Auftraege loeschen: %DiffHrs%:%DiffMin%:%DiffSec%

:: format with leading zeroes
if %DiffSec% LSS 10 (ECHO "LESS 10")else %DiffSec% LSS 1 (ECHO "LESS 1")
::if %DiffSec% LSS 10 (set DiffSec=0%DiffSec%)else [%DiffSec%] LSS 1 (set DiffSec=00)
::if %DiffMin% LSS 10 (set DiffMin=0%DiffMin%)else [%DiffMin%] LSS 1 (set DiffMin=00)
::if %DiffHrs% LSS 10 (set DiffHrs=0%DiffHrs%)else [%DiffHrs%] LSS 1 (set DiffHrs=00)

ECHO 

阅读 395

收藏
2020-07-25

共1个答案

小编典典

1.调试批处理文件
为了调试批处理文件以查找代码中的语法错误,建议在对批处理文件进行每次echo off修改echo ON或从批处理文件中删除或用命令REM注释掉之后,从命令提示符窗口中运行批处理文件。

默认情况下,Windows命令解释器在分析和预处理之后输出每个命令行或整个命令块,(并以匹配开始并以匹配结束,在执行命令行/之前,已对其进行)引用%variable%(立即扩展)的环境变量已替换为环境变量的当前值。块。

@echo off在批处理文件的顶部此默认行为,由此断开@在命令行禁用的开始也这个第一命令行的输出。当批处理文件的开发完成并且批处理文件运行正常时,当然欢迎您。但是,对于调试无法按预期方式运行的批处理文件,最好还查看由命令解释器实际执行的命令行,以找出由于错误而意外退出了批处理文件的执行位置。

在ECHO的行为是在帮助输出解释很简单运行echo /?在命令提示符窗口中。

打开命令提示符窗口会导致以cmd.exe隐式方式启动选项,/K以使命令进程保持运行状态,并在批处理文件或应用程序执行完成后打开控制台窗口。

批处理文件包含exit不带参数的命令是一个例外,/B因为在这种情况下,当前命令进程始终独立于调用层次结构而退出。exit /B是相等的goto :EOF,应该被用来代替正义,exit除非有充分的理由使用正义exitexit /Bgoto :EOF要求两个命令扩展名均在Windows上默认启用。

在一个批处理文件,结果双击在开始cmd.exe与选项/C,以关闭命令过程和它的控制台窗口会自动在应用程序或批处理文件的执行结束独立于为什么一个批处理文件的执行终止的原因。这种自动关闭控制台窗口的行为不利于调试批处理文件,因为批处理文件执行由于语法错误而终止时,看不到错误消息。

有关在命令提示符窗口中运行的Windows命令解释器选项的更多详细信息,请执行以下命令: cmd /?

在运行时和在命令提示窗口中显示的这两个命令的帮助下,说明了如何使用goto :EOF(冒号在这里很重要,作为例外)或exit /B(只是的内部别名goto :EOF)有意退出批处理文件的执行。goto /?exit /?

对于调试更大的批处理文件,使用goto在批处理文件顶部临时添加的代码来跳到某个块,goto :EOF然后在要调试的块后退出批处理可能会有所帮助。

顺便说一句:::是无效的标签,通常用于批处理文件中的注释,因为在执行批处理文件时从不显示标签行。但是在FOR循环的命令块中不能使用标签,因为Windows命令解释器无法正确解释在命令块中带有标签的FOR循环。因此,最好使用命令REM(注释)进行注释,因为该命令是为批处理文件中的注释设计的,并且实际上可以在批处理文件中的任何位置使用。

2.批处理文件中的错误
运行有问题的批处理文件时@ECHO OFF,通过rem @echo off在命令提示符窗口中将其替换为(在文本编辑器中运行替换文件)将其注释掉,可以很容易地看到在哪一行发生错误:

if %DiffSec% LSS 10 (ECHO "LESS 10")else %DiffSec% LSS 1 (ECHO "LESS 1")

如果环境变量的当前值DiffSec不小于,10则ELSE分支由Windows命令解释器执行,该命令以数字开头10。

Windows命令解释器无法在当前目录或环境变量的分号分隔目录列表中指定的任何目录中找到具有该名称的应用程序,该目录PATH具有在环境变量的分号分隔文件扩展名列表中指定的文件扩展名PATHEXT。

此处的错误显然是缺少下一个比较的IF命令。所以正确的代码是

if %DiffSec% LSS 10 (ECHO "LESS 10") else if %DiffSec% LSS 1 ECHO "LESS 1"

在多行写入条件时,这将更容易阅读:

if %DiffSec% LSS 10 (
    ECHO "LESS 10"
) else if %DiffSec% LSS 1 (
    ECHO "LESS 1"
)

语法现在是正确的。

但是第二个条件没有意义,正如JosefZ在其评论中已经提到的那样。如果值为DiffSec10或更大,导致在ELSE分支中执行IF命令,则此条件绝对也不会成立。因此更有意义:

if %DiffSec% LSS 1 (ECHO LESS 1) else if %DiffSec% LSS 10 ECHO LESS 10

或者

if %DiffSec% LSS 1 (
    ECHO LESS 1
) else if %DiffSec% LSS 10 (
    ECHO LESS 10
)

有关批处理文件中有效IF ELSE条件的更多信息,请参见例如

批处理文件中是否存在ELSE语法错误?
批处理脚本-如果使用adb存在./sdcard/file.any

3.为数字<10添加前导零
环境变量始终为字符串类型。对于算术表达式,如果可能,将环境变量的字符串值转换为有符号的32位整数,并且将算术表达式的结果从有符号的32位整数转换回字符串。

同样,IF条件(例如if %DiffSec% LSS 10在执行之前扩展)会if 5 LSS 10导致将5(0x35)从字符串转换为整数,以及10(0x31 0x30)也从字符串转换为整数,以便将两个数字作为整数进行比较。

因此,如果可能的话,避免这种数字比较会更快一些。

在不使用字符串替换真正测试值的情况下,将前导零添加到小于10的数字是很容易的。

首先,环境变量的当前值前面加一个(对于两位数的数字)或更大0(对于3、4甚至更多个数字)。

set "DiffSec=0%DiffSec%"

接下来,从环境变量的当前值到环境变量分配最后的 X个字符(例如2代表两位数字)。

set "DiffSec=%DiffSec:~-2%"

通过在命令提示符窗口中运行,可以在命令SET输出的帮助下解释字符串替换set /?。

两条线的结果是,DiffSec具有用于值099这两条线总是范围内的两位数字后0099

4.解析算术表达式

set /aWindows命令解释器解释的后跟字符串算术表达式与其他字符串完全不同。

空格和制表符是单词分隔符,但没有其他特殊含义。因此,建议使用空格使算术表达式更易读。

然后,在命令提示符窗口中运行时显示的命令SET的帮助下列出了许多运算符set /?。

另外的十进制,八进制和十六进制整数在算术表达式中解释为整数。

最后每隔一个字符串将被解释为环境变量的名称,该环境变量的当前值从字符串转换为整数。

因此,不建议在算术表达式中使用立即扩展或延迟扩展。

%variable%当在命令块内使用环境变量的当前值替换在执行第一个命令之前解析整个命令块时已经存在的变量引用时,在算术表达式内引用环境变量的值就不好。

!variable!在算术表达式内引用环境变量的值也不是一件好事,因为它需要启用延迟扩展,这导致将字符串中的感叹号不再作为文字字符来处理。

因此,最好的办法是始终简单地在算术表达式中写变量名,如果可能,因为变量名不包含空格,并且以不能被Windows解释为整数字符的字符开头,则不要在百分号或感叹号周围加上百分号命令解释器。

另请参见有关在命令行上使用“ set var = text”后为什么没有字符串与“ echo%var%”输出的答案?有关如何使用just setset /P(提示)或set/A(算术表达式)将值分配给环境变量的详细信息。

5.固定和优化的代码

有问题的代码可以固定为此代码进行优化:

@echo off
rem Time Calculation
for /F "skip=1 tokens=1-4" %%A in ('%SystemRoot%\System32\wbem\wmic.exe PATH Win32_LocalTime GET Day^,Hour^,Minute^,Second') do (
    set Day=%%A
    set Hour=%%B
    set Minute=%%C
    set Second=%%D
)
set /A TimeStart=Day * 86400 + Hour * 3600 + Minute *60 + Second

@echo on
%SystemRoot%\System32\ping.exe 8.8.8.8 -n 11
@echo off

for /F "skip=1 tokens=1-4" %%A in ('%SystemRoot%\System32\wbem\wmic.exe PATH Win32_LocalTime GET Day^,Hour^,Minute^,Second') do (
    set Day=%%A
    set Hour=%%B
    set Minute=%%C
    set Second=%%D
)
set /A TimeEnd=Day * 86400 + Hour * 3600 + Minute *60 + Second

set /A TimeDiff=TimeEnd - TimeStart
set /A DiffSec=TimeDiff %% 60
set /A TimeDiff=(TimeDiff - DiffSec) / 60
set /A DiffMin= TimeDiff %% 60
set /A DiffHrs=(TimeDiff - DiffMin) / 60

set "DiffSec=0%DiffSec%"
set "DiffSec=%DiffSec:~-2%"
set "DiffMin=0%DiffMin%"
set "DiffMin=%DiffMin:~-2%"
set "DiffHrs=0%DiffHrs%"
set "DiffHrs=%DiffHrs:~-2%"

echo Time needed for orders deletion: %DiffHrs%:%DiffMin%:%DiffSec%

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • echo /?
  • for /?
  • ping /?
  • rem /?
  • set /?
  • wmic /?
  • wmic path /?
2020-07-25