2

I've seen a lot of answers to this question using a for-loop for writing a program's output line by line into a variable. This is pretty much exactly what I need BUT from what I understand it relies on the program terminating and then being able to iterate over a known number of lines.

My case is this: I have a program "example.exe" that will not terminate on its own but continuously output lines of data. I will run this program from a batch script with a few arguments and I want the lines of this program to end up in a variable "LINE" so that whenever there is a new output by that program I want the "LINE" to update and run a few extra lines of code doing something with the new set variable.

in pseudo code:

Set LINE=*example.exe output*
echo %LINE%
... some more operations on LINE

How can I achieve this without having to terminate "example.exe" and preferably without having to pipe everything into a file and then reading back from that file?

Jeffrey
  • 189
  • 1
  • 8

1 Answers1

3

If you are restricting yourself to native batch commands, then any answer is going to require reading the input with SET /P, which has a limit of 1021 bytes per line. If your output exceeds 1021 bytes per line, then this is not possible with pure batch.

It is not too hard to accomplish your task if your exe program writes some unique string at the end that signifies it has finished.

For this demo I will substitute a little batch script for the exe file. The batch script (:sender routine) will simply echo any input you provide, and will terminate when you enter QUIT.

A :receiver routine will read and process lines until it receives QUIT.

I simply pipe the :sender output to :receiver :-)

@echo off
setlocal enableDelayedExpansion
if "%~1" == ":sender" goto :sender
if "%~1" == ":receiver" goto :receiver
"%~f0" :sender | "%~f0" :receiver
exit /b

:sender
set "str="
set /p "str=>" >&2
echo(!str!
if !str! neq QUIT goto :sender
exit /b

:receiver
set "LINE="
set /p "LINE="
echo LINE=!LINE!
REM do whatever...
if !LINE! neq QUIT goto :receiver
exit /b

-- SAMPLE I/O --

>Hello world!
LINE=Hello world!
>    This is a test
LINE=    This is a test
>
LINE=
>Almost done
LINE=Almost done
>QUIT
LINE=QUIT

For your use you would simply substitute your exe file for the :sender in the pipe

yourProgram.exe | "%~f0" :receiver

If your exe file truly runs "forever", then you can take out the QUIT logic. But then I believe you will have to kill your console when you are ready to terminate - Ctrl+C will not work to kill the :receiver.

Things are more complicated if you want to automatically detect and terminate the pipe when there is no more input, without reliance on a unique termination string. The solution is very similar to my implementation of a batch tee program. I'll leave it up to you to adapt batchTee.bat to your situation :-)

Developer Guy
  • 2,318
  • 6
  • 19
  • 37
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Hey there! Thanks for the very elaborate answer. Sadly I can't seem to get it to work. I substituted the receiver for my exe but it just starts the exe and not the second script. Only after I cancel the exe with ^C it starts the second script which just outputs "LINE=" in an endless loop. – Jeffrey Mar 25 '18 at 20:13
  • I assumed your exe is a console program that sends output to stdout. What happened to your exe output? Did you see it in any way? If you can pipe your output to FINDSTR as `yourExe | findstr /n "^"`(each line should be prefixed with a line number), then it should work with my receiver. If not, then I don't know what will work with your exe. – dbenham Mar 26 '18 at 03:44
  • As I suspected your answer was indeed exactly what I needed but I had to make a tiny adaptation to get it to work in my case. I'll get to that later. I accepted your answer as it helped me figuring everything out. Still I would kindly ask you to add annotations to all the lines explaining what they do as I am sure it would teach people reading this post and me a lot about batch scripts. It took me some time to figure out that we are actually calling the script itself from within itself . – Jeffrey Mar 26 '18 at 22:21
  • That aside thanks a lot for a very detailed and helpful answer! You did guess right about my app it is a pure console application but it doesn't output to stdout. Since you mentioned it I did some research and found out that almost all output goes to stderr so in my case I had to pipe like this: `yourProgram.exe 2>&1 | "%~f0" :receiver` Would you also add that as an option to your answer for people stuck at a similar problem? – Jeffrey Mar 26 '18 at 22:23