如何使此powershell命令在循环内批量工作?

时间:2019-01-01 10:08:04

标签: powershell batch-file

试图找到差异。但是,当此powershell命令位于findstr中时,它将失败。它自己返回正确的值。另外,没有循环,它会返回正确的值。

echo:!newvalue!| findstr /R "^[0123456789][0123456789]\.[0123456789]$" >nul
  if errorlevel 1 (
    set newvalue=
  ) else (
    FOR /F "usebackq delims=" %%i IN (`powershell -nop -c "'{0:n1}' -f (%newvalue% - 12.0)"`) DO (SET difference=%%i)
    echo %difference%
  )

任何人都可以找出我的缺失/错误吗?

谢谢。

2 个答案:

答案 0 :(得分:2)

我建议阅读How does the Windows Command Interpreter (CMD.EXE) parse scripts?

在使用此命令块解析命令行时,Windows命令处理器在命令块内使用语法%variable%替换所有环境变量引用,该命令块以(开头并以匹配的)结尾。这意味着 IF 命令的 ELSE 分支命令块内的命令行echo %difference%在命令 IF 之前被cmd.exe修改了>完全执行。 %difference%被环境变量difference的当前值替换,或者在环境变量difference未在 IF 条件以上的位置定义的情况下为空字符串。在后一种情况下,echo 是在解析命令块之后保留的命令行,因此显示了命令回显的状态,而不是上面命令行中分配给环境变量difference的字符串值。已启用延迟的环境变量扩展的解决方案是在 ELSE 命令块中使用echo !difference!

无需使用PowerShell即可解决此浮点减法的解决方案:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
if defined NewValue goto Validate

:UserPrompt
set /P "NewValue=Enter value between 00.0 and 99.9: "

:Validate
echo:!NewValue!| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 set "NewValue=" & goto UserPrompt

for /F "tokens=1,2 delims=." %%I in ("%NewValue%") do set "PreComma=%%I" & set "PostComma=%%J"
set /A Difference=1%PreComma% - 112
set "Difference=%Difference%.%PostComma%"
echo Difference is: %Difference%
endlocal

在确认分配给环境变量NewValue的字符串确实由两位数字组成后,在How can I do a negative regex match in batch?处请求并期望并描述了该数字,然后将浮点数字符串拆分.上的逗号分隔成逗号前后的数字字符串。

使用算术表达式将逗号前的数字减去12。但是,必须考虑到cmd.exe在算术表达式的评估中将前导0的整数解释为八进制数。对于0007来说没问题。但是0809将是无效的八进制数,因此,如果在批处理文件中仅使用0,则Windows命令处理器将使用值set /A Difference=PreComma - 12导致错误的减法结果。解决方法是将字符串1与逗号前字符串连接到范围为100199的数字字符串,并减去112以得到正确的结果。

不需要修改逗号后的值,因此最终Difference的值是通过将算术表达式的结果与未修改的逗号后的字符串连接而最终确定的。

通过在Difference上方插入以下附加命令行,也可以始终以两位数来获得echo Difference is: %Difference%值:

if %Difference:~0,1% == - (
    if %Difference:~2,1% == . set "Difference=-0%Difference:~1%"
) else (
    if %Difference:~1,1% == . set "Difference=0%Difference%"
)

该解决方案还避免了PowerShell的浮点结果根据区域和语言设置格式化的问题。例如,在德国和奥地利,十进制符号,而不是.,这意味着PowerShell为15.3 - 12.0输出的减法结果是3,3,并且不是3.3

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

  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?

另请参阅single line with multiple commands using Windows batch file

答案 1 :(得分:0)

从技术上讲,这不是一个答案,因为您已经收到并接受了一个非常好的答案。

这只是让您看到一种从文件中提取字符串,在小数点处分割并从大于或等于{{1}的整数中减去12的方法},(对于小于12的整数,请参见接受的答案),且都没有'loop'或12

PowerShell

很显然,在您的脚本中,您只需要:

@Echo Off

Rem Create a variable from the first line of your file
Set /P "newvalue="<"file.tmp"
Echo [%newvalue%]

Rem Exit if the string 'value' does not exist in '%newvalue%'
If "%newvalue%"=="%newvalue:*value=%" Exit /B

Rem ReSet the variable to everything after the string 'value'
Set "newvalue=%newvalue:*value=%"
Echo [%newvalue%]

Rem ReSet the variable to everything up to the first 'space' character
Set "newvalue=%newvalue: ="&:"%"
Echo [%newvalue%]

Rem ReSet the variable, removing the unneeded leading '=' character
Set "newvalue=%newvalue:~1%"
Echo [%newvalue%]

Rem Set a new variable to the whole number, i.e. everything up to the first '.' character
Set "whole=%newvalue:.="&:"%"
Echo [%whole%]

Rem Set a new variable to the decimal, i.e. everything after the '.' character
Set "decimal=%newvalue:*.=%"
Echo [%decimal%]

Rem Subtract 12 from the whole number
Set /A remainder=100+whole-112
Echo [%remainder%]

Rem ReJoin the variables to show the difference
Echo [%remainder%.%decimal%]

Pause