Set /P

Microsoft Windows
Post Reply
User avatar
MigrationUser
Posts: 336
Joined: 2021-Jul-12, 1:37 pm
Contact:

Set /P

Post by MigrationUser »

11 Sep 2006 19:00
gpl

This site is an incredible resource, many thanks.

In my browsings, I came across this very useful addition to the tricks with SET

To place the first line of a file into a variable, do this

Set /P MyVar=<aFilename

Or the first line of piped output

Date /t|Set /P MyVar=

Now that is far simpler and more elegant than a For loop to parse a file or parse the putput of a command (assuming you only want the first line)

Cheers
Graham

----------------------------

#2 11 Sep 2006 19:38
Simon Sheppard


That looks useful - I guess you could also get the last line with SORT /r

----------------------------
#3 22 Dec 2006 17:49
Simon Sheppard
gpl wrote:

This site is an incredible resource, many thanks.

In my browsings, I came across this very useful addition to the tricks with SET

To place the first line of a file into a variable, do this

Set /P MyVar=<aFilename

Or the first line of piped output

Date /t|Set /P MyVar=

Now that is far simpler and more elegant than a For loop to parse a file or parse the putput of a command (assuming you only want the first line)

Cheers
Graham
I've added this to the examples on the SET page
https://ss64.com/nt/set.html

----------------------------

#4 03 Jan 2007 04:00
iceman


Hi guys,

I tried this on XP Professional 2002 SP2 and XP Home Edition SP2. I also tried putting it into a .bat file that was terminated immediately following the '=' sign. I cannot seem to get it to work. I do have the extended command set, becuase "help set" results in and explanation of Set /P. Here it the resulting output of the pipe trick:

Code: Select all

C:\>set MyVar=test

C:\>Date /t|Set /P MyVar=

C:\>set MyVar
MyVar=test

C:\>
----------------------------

#5 03 Jan 2007 10:50
bluesxman


Hmm, same here (tried with Win2000 cmd.exe too) ... though the "Set /P MyVar=<aFilename" method does work as expected. My best guess (and I could be way off with this) is that when you pipe output the first thing it sends is a "CR" character, which "set /p" reads as a blank line, and duly does nothing with the variable. Unless anyone else has any other bright ideas?

cmd | *sh | ruby | chef

----------------------------

#6 03 Jan 2007 11:39
Simon Sheppard


^ Thats strange, Im sure I got this to work before, but that second syntax doesn't work for me either

----------------------------

#7 04 Feb 2007 13:10
Al


same, same here :(

Code: Select all

@echo off

verify other >&2 nul
echo foo | set /p bar=
if ERRORLEVEL 1 echo Error %ERRORLEVEL%
echo %bar%
set bar

goto :EOF
and let me draw your attention - ERRORLEVEL reset to zero, so set command thinks everything is ok, therefore this negates bluesxman's CR assumption above.

i'm still looking for solution of this puzzle as passing strings via files is deprecated in my environment and using set is clumse a little

ps: behaviour confirmed with Win2000 & Win2003



UPDATE
amending set /p invoke as
echo foo | set /p bar= | title foo | tlist | find /i "foo"
yields interesting result which lets me speculate about | pipeline creates new context, succesfully sets variable there and then leaves context losing changes

could you please confirm or just share your thoughts

Last edited by Al (04 Feb 2007 13:27)

----------------------------

#8 04 Feb 2007 18:37
Simon Sheppard


The method I normally use to get the output of one command into another is FOR /F

People often think of this as just a looping command, but you can perform a single loop to pull out the values you want

e.g.

FOR /F "tokens=4*" %%G IN ('ver') DO SET _version=%%G

FOR /F "tokens=*" %%G IN ('echo here i am') DO SET _message=%%G

see
https://www.ss64.com/nt/for_cmd.html

----------------------------

#9 02 Mar 2007 21:14
Dan9999


I agree that the | should work with SET /p like so:

set myvar=
echo result | set /p myvar=

but it doesn't. What is weird, and works is this:

--- begin file setmyvar.cmd
set /p myvar=
echo %myvar%
--- end file

then type
echo result | cmd /c setmycar.cmd

It looks like the | redirection will work for cmd but not the set command. Not very helpful but interesting nonetheless. I wonder if this could be brought further.....

----------------------------

#10 02 Mar 2007 21:20
Dan9999


ok, I found out why myself. it's because the | creates a new context so the variable never makes it out to the rest of the current context.

proof:
set bar=
echo aaa | (set /p bar= && set bar)
set bar

----------------------------

#11 19 Sep 2011 22:41
Simon Sheppard


some further discussion of this over on alt.msdos.batch.nt
https://groups.google.com/g/alt.msdos.b ... l=en&pli=1

----------------------------

#12 25 Sep 2011 23:32
jeb


In a short form:

Even if SET/p doesn't works very useful and/or reliable with pipes, it does with redirects!
This one fails, as both sides of a pipe are started in a new asynchronous context.

Code: Select all

(
echo one
echo two) | ( set /p Line1=
set /p Line2=
set Line
)
But this one works very well

Code: Select all

(echo one
echo two) > myTemp.txt

<myTemp.txt (
set /p Line1=
set /p Line2=
set Line
)
And set/p can read also content with exclamation marks without modification, even empty lines.
Both are tricky with a standard FOR/F loop.

jeb

----------------------------

#13 26 Sep 2011 13:02
bluesxman


I tried (and succeeded) in creating a "set /p" loop to read the contents of a file of arbitrary length a while back, it went something like this:

Code: Select all

@echo off

REM clear the data array
for /f "usebackq tokens=1 delims==" %%a in (`set read_`) do set %%a=

set "data=%~dpn0.dat"
set line=0

REM find the length of the file (this is important otherwise we don't know when to stop!)
for /f "usebackq tokens=1" %%a in (`type "%data%" ^| find /c /v ""`) do set maxlines=%%a

call :loop < "%data%"
call :display

pause

goto :EOF

:loop

set /a line+=1
set /p read_%line%=

if %line% LEQ %maxlines% goto :loop

goto :EOF

:display

echo:%0

for /l %%a in (1,1,%maxlines%) do (
	set /p "out=Line #%%a = "<nul
	if defined read_%%a call set /p "out=%%read_%%a%%" <nul
	echo:
)

goto :EOF
(having just re-written that I've realised it was somewhat more complicated a proposition than I remembered :)

But while effective, I found it to be a fair bit slower than using as "FOR /F" loop.
Post Reply