Strange behavior of SET /P

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Alogon
Posts: 4
Joined: 06 Apr 2020 19:22

Strange behavior of SET /P

#1 Post by Alogon » 25 Sep 2021 23:01

Code: Select all

if 1==1 (
  set A=
  set /P A= [in parens] What shall A be?
  echo A=%A%
  )
set A=
set /P A=[not in parens] What shall A be?
echo A=%A%
Only the second set /P works properly. When the statement is in a parenthesized block, it does not set the variable.

While experimenting just now, I noticed two other anomalies. First, if the prompt string contains parentheses, they will probably produce an error. I originally wrote "(in parens)" instead of "[in parens]" and got the message "What was unexpected at this time."

Second, one of my attempted replies to the prompt was "hi". I happen to have a Doskey macro installed called HI. The value of A became the text of the macro line.

I'm already acquainted with a third caution: if the variable to be set is local but not yet existing, and there is a global variable with the same name, and the user just responds to the prompt with <enter>, then the variable will not be created. The program will instead reference the global variable. Hence it should be initialized before the set /P command. But in this example, the initialization within parentheses doesn't seem to work, either.

I hesitate even to predict what will happen under various circumstances. Either there is something rather basic that I don't understand about set /P, or the use of parentheses, or setlocal, or this is an unusually flaky command that must be used with caution. Can someone shed some light on my confusion?

ShadowThief
Expert
Posts: 1160
Joined: 06 Sep 2013 21:28
Location: Virginia, United States

Re: Strange behavior of SET /P

#2 Post by ShadowThief » 25 Sep 2021 23:30

You're trying to set and use a variable within the same code block. By default, variables are expanded when the script is parsed, but things inside of parentheses are treated as a single command so %A% gets expanded to nothing because that's its value before the code block.

To tell the interpreter to expand the variables when the line is executed instead, enable delayed expansion and use the !A! syntax instead.

Code: Select all

@echo off
setlocal enabledelayedexpansion
if 1==1 (
  set A=
  set /P A= [in parens] What shall A be?
  echo A=!A!
  )
set A=
set /P A=[not in parens] What shall A be?
echo A=%A%

OJBakker
Expert
Posts: 88
Joined: 12 Aug 2011 13:57

Re: Strange behavior of SET /P

#3 Post by OJBakker » 26 Sep 2021 05:38

Use double quotes with the set command to avoid the errors with parentheses.
Use 'call echo' or 'set A' to see the up-to-date values of a variable in a () codeblock if you don't use delayed expansion.

Code: Select all

if 1==1 (
  set A=
  set /P "A= (in parens) What shall A be?"
  echo A=%A%
  rem 'call echo' shows the uptodate value of variable A
  @call echo A=%%A%%
  rem 'set A' shows all variables starting with A with their values
  @set A
  rem next line limits the output of 'set A' to just your variable A
  @if defined A @for /f "tokens=1,2* delims==" %%P in ('set A') do @if "%%P" == "A" @echo A=%%Q
  )
set A=
set /P "A=(not in parens) What shall A be?"
echo A=%A%
pause

Post Reply