最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

windows - Why does an environment variable reference expand always to 1 on repeated batch execution? - Stack Overflow

programmeradmin5浏览0评论

Task description

Prompt the user to enter their age in years, save the users response as a variable age.

  • If the user did not provide a response like an empty string or letters or characters echo a message invalid and exit with script with an echo message: not ok
  • However if the user's age is greater than or equal to 16, output the message: You may drive
  • If the user's age is less than 16 then subtract their input age with 16 and output: You may not drive for (whatever the result of the 16 subtracted by their input age) year
  • Exit at the end of the script with an echo ok.

Batch script

@echo off
setlocal

:: Prompt the user to enter their age
set /p age="Enter your age in years: "

:: Check if the age is a valid number (not empty and contains only digits)
for /f "delims=0123456789" %%a in ("%age%") do set "invalid=1"
if "%invalid%"=="1" (
echo invalid
echo not ok
exit /b
)

:: Check if age is greater than or equal to 16
if %age% geq 16 (
echo You may drive
) else (
set /a yearsLeft=16-%age%
echo You may not drive for %yearsLeft% year(s)
)

:: Exit with a message
echo ok
exit /b

Issue description

I was expecting the script to work, but it keeps outputting on repeated execution from within a command prompt window:

Enter your age in years: 2
invalid
not ok

Why does the if condition below the for loop always evaluate to true?

Task description

Prompt the user to enter their age in years, save the users response as a variable age.

  • If the user did not provide a response like an empty string or letters or characters echo a message invalid and exit with script with an echo message: not ok
  • However if the user's age is greater than or equal to 16, output the message: You may drive
  • If the user's age is less than 16 then subtract their input age with 16 and output: You may not drive for (whatever the result of the 16 subtracted by their input age) year
  • Exit at the end of the script with an echo ok.

Batch script

@echo off
setlocal

:: Prompt the user to enter their age
set /p age="Enter your age in years: "

:: Check if the age is a valid number (not empty and contains only digits)
for /f "delims=0123456789" %%a in ("%age%") do set "invalid=1"
if "%invalid%"=="1" (
echo invalid
echo not ok
exit /b
)

:: Check if age is greater than or equal to 16
if %age% geq 16 (
echo You may drive
) else (
set /a yearsLeft=16-%age%
echo You may not drive for %yearsLeft% year(s)
)

:: Exit with a message
echo ok
exit /b

Issue description

I was expecting the script to work, but it keeps outputting on repeated execution from within a command prompt window:

Enter your age in years: 2
invalid
not ok

Why does the if condition below the for loop always evaluate to true?

Share Improve this question edited 2 days ago Basilevs 24.2k16 gold badges60 silver badges106 bronze badges asked Mar 26 at 18:24 Theone uneedtoknowTheone uneedtoknow 11 3
  • 3 %invalid% might still be defined from previous experiments (check with set invalid). Be sure to delete it before the for /f loop with set "invalid=" – Stephan Commented Mar 27 at 6:53
  • 1 A user input like ;12 is additionally not detected as invalid because of ; is the default end of line character resulting in ignoring the value of environment variable age. A user input with " breaks the entire batch script execution and can even result in executing commands not written in the batch file at all. The definition of yearsLeft and its usage in same command block results in running into the delayed expansion trap with output of no year value or the year value from a previous execution of the batch file or something else. – Mofi Commented Mar 27 at 7:10
  • I would strongly advise, especially as you are clearly new to scripting batch files, that you indent your code. It is easier to read, and means mistakes such as unbalanced parentheses are less likely to occur. – Compo Commented Mar 27 at 14:26
Add a comment  | 

2 Answers 2

Reset to default 1

Here is a rewritten working code:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
goto UserPrompt

:InvalidAge
echo You have not entered a valid age as number in whole years
echo using only the digits 0 to 9 like 20 or 36 or 57.
echo(
echo "thirteen" is incorrect, the number 13 would be correct.
echo "12.5" is incorrect, the number 12 would be correct.
echo "16¼" is incorrect, the number 16 would be correct.

rem Prompt the users to enter their age.
:UserPrompt
echo(
set "age="
set /P "age=Enter your age as number in years: " || goto UserPrompt
rem Remove all double quotes from user input string.
set "age=%age:"=%"
if not defined age goto UserPrompt

rem Check if the age is a valid number, i.e. has only digits.
for /F delims^=0123456789^ eol^= %%I in ("%age%") do goto InvalidAge
for /F "tokens=* delims=0" %%I in ("%age%") do set "age=%%I"
if not defined age set "age=0"
if %age% GTR 120 goto InvalidAge
if %age% GEQ 16 goto Process

set /A YearsLeft=16-age
if %YearsLeft% == 1 (set "PluralS=") else set "PluralS=s"
echo You may not drive for %YearsLeft% year%PluralS%.
exit /B

:Process
echo Okay! You may drive.
endlocal

For an explanation of the code read:

  • How to stop Windows command interpreter from quitting batch file execution on an incorrect user input?
  • Safe number comparison in Windows batch file

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

  • echo /?
  • endlocal /?
  • exit /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?

PS: The character ¼ must be character encoded according to the code page used by default in command prompt windows by the user accounts using this batch file like OEM 850 or OEM 437.

Given that we are dealing with user input that does not include unbalanced rabbit's ears, % or other language-sensitive characters,

@ECHO Off
SETLOCAL

SET /p "age=Your age :"

FOR /L %%e IN (16,1,120) DO IF "%%e"=="%age%" GOTO candrive
FOR /L %%e IN (0,1,15) DO IF "%%e"=="%age%" SET /a wait4=16-%%e&GOTO wait
ECHO Invalid input
GOTO :eof

:wait
SET "plural="
IF %wait4% geq 2 SET "plural=s"
ECHO IN %wait4% year%plural%,
:candrive
ECHO you can drive
ECHO once you get a licence.

GOTO :EOF

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论