Ответ 1
Ваша попытка вызвать пакетную функцию внутри канала всегда будет терпеть неудачу из-за того, как работают трубы Windows - Windows запускает обе стороны канала через новые CMD-оболочки. Подробнее см. fooobar.com/info/6270/....
То, что Роб ван дер Вуде версия пакетного тройника не может работать для вас, потому что она использует FOR /F
для чтения результатов команды - команда должна выполнить до завершения, прежде чем читать строки. Это не сработает, если вам потребуется взаимодействие с пользователем во время выполнения команды. С этой версией tee вы можете просто перенаправить вывод в файл, а затем TYPE
файл по окончании. Очевидно, что вы не хотите.
Есть чистые пакетные трюки, которые могут приблизить вас, но я думаю, что есть еще одна проблема, которая не может быть решена с помощью чистой партии. Ваш исполняемый файл может вывести приглашение на строку без создания новой строки. Я считаю, что чистая нативная партия всегда читает целые строки (кроме случаев, когда в конце потока). Я не знаю, как пакетный метод читать символ по символу.
Незначительная коррекция - SET /P
может читать частичные строки входного потока, но у него есть ограничения, которые препятствуют его использованию для надежного решения пакетного тройника: нет никакого способа точно знать, когда каждая строка заканчивается. Он ограничен 1021 символом на "линию". Он разбивает управляющие символы с конца каждой "линии". Невозможно сказать, когда он достигнет конца входного потока.
Но есть простое решение - JScript или VBScript работает как чемпион и не требует специальных настроек. Вот гибридный JScript/пакет script, который должен работать для вас. JScript плохо написан с большим количеством возможностей для улучшения. Например, проверка ошибок отсутствует.
Я сохраняю script как tee.bat
. Первый требуемый аргумент указывает имя файла для записи. По умолчанию файл переписан, если он уже существует. Если предоставляется второй аргумент (значение не имеет значения), то вместо этого вывод добавляется к файлу.
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
::--- Batch section within JScript comment that calls the internal JScript ----
@echo off
cscript //E:JScript //nologo "%~f0" %*
exit /b
----- End of JScript comment, beginning of normal JScript ------------------*/
var fso = new ActiveXObject("Scripting.FileSystemObject");
var mode=2;
if (WScript.Arguments.Count()==2) {mode=8;}
var out = fso.OpenTextFile(WScript.Arguments(0),mode,true);
var chr;
while( !WScript.StdIn.AtEndOfStream ) {
chr=WScript.StdIn.Read(1);
WScript.StdOut.Write(chr);
out.Write(chr);
}
Использование в значительной степени похоже на то, что вы ожидаете.
command.exe | tee.bat output.txt 1
Последний 1 аргумент принудительно добавляет режим добавления. Это может быть любое значение, кроме 1
Можно поместить все в один пакет script, как вам кажется.
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
::--- Batch section within JScript comment ----------------------------
@echo off
::This block of code handles the TEE by calling the internal JScript code
if "%~1"=="_TEE_" (
cscript //E:JScript //nologo "%~f0" %2 %3
exit /b
)
::The rest of your batch script goes here
::This pipes to TEE in append mode
mycommand.exe | "%~f0" _TEE_ output.txt 1
exit /b
----- End of JScript comment, beginning of normal JScript ------------------*/
var fso = new ActiveXObject("Scripting.FileSystemObject");
var mode=2;
if (WScript.Arguments.Count()==2) {mode=8;}
var out = fso.OpenTextFile(WScript.Arguments(0),mode,true);
var chr;
while( !WScript.StdIn.AtEndOfStream ) {
chr=WScript.StdIn.Read(1);
WScript.StdOut.Write(chr);
out.Write(chr);
}
Обновление
Для тех, у кого есть академический интерес к пакетному сценарию, я опубликовал чистую исходную пакетную версию tee в Асинхронный родной пакет tee script в DosTips. Но этот гибридный подход - мое предпочтительное решение для сценариев.