简体   繁体   中英

How to make this powershell command work inside a loop in batch?

Trying to find the difference. But when this powershell command is inside in the findstr, it fails. On its own, it returns the correct value. Also, without the loop, it returns the correct value.

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%
  )

Can anyone figure out what I'm missing/did wrong?

Thanks in advance.

I recommend reading How does the Windows Command Interpreter (CMD.EXE) parse scripts?

Windows command processor replaces all environment variable references using syntax %variable% inside a command block starting with ( and ending with matching ) already on parsing the command line using this command block. This means the command line echo %difference% inside ELSE branch command block of the IF command is modified by cmd.exe before command IF is executed at all. %difference% is replaced by current value of environment variable difference or an empty string in case of environment variable difference is not defined somewhere above the IF condition. In latter case echo is the command line remaining after parsing the command block and therefore shows status of command echoing instead of the string value assigned to environment variable difference in the command line above. The solution with already enabled delayed environment variable expansion is using echo !difference! in ELSE command block.

A solution for this floating point subtraction without usage of PowerShell can be seen below:

@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

After validating that the string assigned to environment variable NewValue indeed consists of two digits, a point and one more digit as requested and expected and described at How can I do a negative regex match in batch? , the floating point number string is split up on . into pre-comma and post-comma number strings.

The pre-comma number is subtracted by 12 using an arithmetic expression. But it must be taken into account that an integer number with a leading 0 is interpreted by cmd.exe on evaluation of the arithmetic expression as octal number. That is no problem for 00 to 07 . But 08 and 09 would be invalid octal numbers and so Windows command processor would use value 0 resulting in a wrong subtraction result if simply set /A Difference=PreComma - 12 would have been used in batch file. The workaround is concatenating the string 1 with the pre-comma string to a number string in range 100 to 199 and subtract 112 to get the correct result.

The post-comma value does not need to be modified and so the Difference value is determined finally with concatenating the result of the arithmetic expression with the unmodified post-comma number string.

It is possible to get the Difference value also always with two digits by inserting following additional command lines above 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%"
)

This solution avoids also the problem that floating point result of PowerShell is formatted according to region and language settings. For example in Germany and Austria the decimal symbol is , and not . which means the subtraction result output by PowerShell for 15.3 - 12.0 is 3,3 and not 3.3 .

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

See also single line with multiple commands using Windows batch file .

This is not technically an answer, as you've already received and accepted one a perfectly good one.

It is just to allow you to visualise a method of taking the string from your file, splitting it at the decimal point and subtracting 12 , from a whole number greater or equal to 12 , (see the accepted answer for whole numbers less than 12 ) , all without 'loops' or 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

Obviously in your script proper, you'd only need:

@Echo Off
Set /P "newvalue="<"file.tmp"
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Set "newvalue=%newvalue:*value=%"
Set "newvalue=%newvalue: ="&:"%"
Set "newvalue=%newvalue:~1%"
Set "whole=%newvalue:.="&:"%"
Set "decimal=%newvalue:*.=%"
Set /A remainder=100+whole-112
Echo %remainder%.%decimal%
Pause

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM