Как записать вывод все еще работающей программы в переменную в пакетном файле Windows 10

Я видел много ответов на этот вопрос с использованием цикла for для записи вывода программы построчно в переменную. Это в значительной степени именно то, что мне нужно, НО, насколько я понимаю, это зависит от завершения программы, а затем от возможности перебирать известное количество строк.

Мой случай таков: у меня есть программа «example.exe», которая не завершается сама по себе, а постоянно выводит строки данных. Я буду запускать эту программу из пакетного сценария с несколькими аргументами, и я хочу, чтобы строки этой программы заканчивались переменной «LINE», чтобы всякий раз, когда появляется новый вывод этой программы, я хотел, чтобы «LINE» обновлялась и запустите несколько дополнительных строк кода, делающих что-то с новой переменной set.

в псевдокоде:

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

Как я могу добиться этого без необходимости завершать «example.exe» и, желательно, без необходимости передавать все в файл и затем считывать из этого файла?


person Jeffrey    schedule 24.03.2018    source источник
comment
связано   -  person Stephan    schedule 24.03.2018


Ответы (1)


Если вы ограничиваете себя собственными пакетными командами, то любой ответ потребует чтения ввода с помощью SET /P, который имеет ограничение в 1021 байт на строку. Если ваш вывод превышает 1021 байт на строку, то это невозможно с чистым пакетом.

Выполнить задачу несложно, если исполняемая программа записывает в конце какую-то уникальную строку, означающую, что она завершена.

Для этой демонстрации я заменю исполняемый файл небольшим пакетным скриптом. Пакетный сценарий (программа:sender) будет просто повторять любой введенный вами ввод и завершится, когда вы нажмете QUIT.

Подпрограмма :receiver будет читать и обрабатывать строки, пока не получит QUIT.

Я просто передаю вывод :sender в :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

-- ОБРАЗЕЦ В/В --

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

Для вашего использования вы просто замените свой exe-файл на :sender в канале

yourProgram.exe | "%~f0" :receiver

Если ваш исполняемый файл действительно работает «навсегда», вы можете отключить логику QUIT. Но тогда я полагаю, что вам придется убить вашу консоль, когда вы будете готовы завершить работу - Ctrl+C не сработает, чтобы убить :receiver.

Ситуация усложняется, если вы хотите автоматически обнаруживать и завершать канал, когда больше нет входных данных, не полагаясь на уникальную строку завершения. Решение очень похоже на мою реализацию пакетной программы. Я оставлю вам возможность адаптировать batchTee.bat к вашей ситуации :-)

person dbenham    schedule 24.03.2018
comment
Привет! Спасибо за очень развернутый ответ. К сожалению, я не могу заставить его работать. Я заменил приемник на свой exe, но он просто запускает exe, а не второй скрипт. Только после того, как я отменяю exe с помощью ^C, он запускает второй скрипт, который просто выводит LINE= в бесконечном цикле. - person Jeffrey; 25.03.2018
comment
Я предположил, что ваш exe — это консольная программа, которая отправляет вывод на стандартный вывод. Что случилось с вашим exe выходом? Вы это как-то видели? Если вы можете направить свой вывод в FINDSTR как yourExe | findstr /n "^" (каждая строка должна иметь префикс с номером строки), то он должен работать с моим приемником. Если нет, то я не знаю, что будет работать с вашим exe. - person dbenham; 26.03.2018
comment
Как я и подозревал, ваш ответ действительно был именно тем, что мне было нужно, но мне пришлось сделать небольшую адаптацию, чтобы заставить его работать в моем случае. Я вернусь к этому позже. Я принял ваш ответ, так как он помог мне во всем разобраться. Тем не менее, я хотел бы попросить вас добавить аннотации ко всем строкам, объясняющие, что они делают, поскольку я уверен, что это научит людей, читающих этот пост, и меня, многому о пакетных сценариях. Мне потребовалось некоторое время, чтобы понять, что на самом деле мы вызываем сам скрипт из самого себя. - person Jeffrey; 27.03.2018
comment
В остальном большое спасибо за очень подробный и полезный ответ! Вы правильно догадались о моем приложении, это чисто консольное приложение, но оно не выводится на стандартный вывод. Поскольку вы упомянули об этом, я провел небольшое исследование и обнаружил, что почти весь вывод идет на stderr, поэтому в моем случае мне пришлось передать это следующим образом: yourProgram.exe 2>&1 | "%~f0" :receiver Не могли бы вы также добавить это в качестве опции к своему ответу для людей, застрявших на похожей проблеме? - person Jeffrey; 27.03.2018