2012-05-23 7 views
10

Я пытаюсь использовать код tee, написанный для файла bat, но у меня возникли проблемы с его реализацией в моем коде. Я не хочу использовать сторонние установки для решения проблемы с tee, так как я хочу, чтобы код работал, если я отформатирую свой компьютер через год и хочу снова запустить программу.Использование пользовательской команды Tee для .bat-файла

Я его установка таким образом:

mycommand.exe | tee.bat -a output.txt 

Я попытался с отдельным .bat файлом и попытался в то числе в виде функции (предпочтительно) в оригинальной .bat без толка с:

myprogram.exe | call tee -a output.txt 
echo. 
echo. 
echo. 
SET /P restart="Do you want to run again? (1=yes, 2=no): " 
if "%restart%"=="1" GOTO LoopStart 


::-------------------------------------------------------- 
::-- Function section starts below here 
::-------------------------------------------------------- 
:tee 
:: Check Windows version 
IF NOT "%OS%"=="Windows_NT" GOTO Syntax 
| 
:: Keep variables local 
SETLOCAL 

:: Check command line arguments 
SET Append=0 
IF /I [%1]==[-a] (
    SET Append=1 
    SHIFT 
) 
IF  [%1]==[] GOTO Syntax 
IF NOT [%2]==[] GOTO Syntax 

:: Test for invalid wildcards 
SET Counter=0 
FOR /F %%A IN ('DIR /A /B %1 2^>NUL') DO CALL :Count "%%~fA" 
IF %Counter% GTR 1 (
    SET Counter= 
    GOTO Syntax 
) 

:: A valid filename seems to have been specified 
SET File=%1 

:: Check if a directory with the specified name exists 
DIR /AD %File% >NUL 2>NUL 
IF NOT ERRORLEVEL 1 (
    SET File= 
    GOTO Syntax 
) 

:: Specify /Y switch for Windows 2000/XP COPY command 
SET Y= 
VER | FIND "Windows NT" > NUL 
IF ERRORLEVEL 1 SET Y=/Y 

:: Flush existing file or create new one if -a wasn't specified 
IF %Append%==0 (COPY %Y% NUL %File% > NUL 2>&1) 

:: Actual TEE 
FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO (
    > CON ECHO.%%B 
    >> %File% ECHO.%%B 
) 

:: Done 
ENDLOCAL 
GOTO:EOF 


:Count 
SET /A Counter += 1 
SET File=%1 
GOTO:EOF 


:Syntax 
ECHO. 
ECHO Tee.bat, Version 2.11a for Windows NT 4/2000/XP 
ECHO Display text on screen and redirect it to a file simultaneously 
ECHO. 
IF NOT "%OS%"=="Windows_NT" ECHO Usage: some_command ¦ TEE.BAT [ -a ] filename 
IF NOT "%OS%"=="Windows_NT" GOTO Skip 
ECHO Usage: some_command ^| TEE.BAT [ -a ] filename 
:Skip 
ECHO. 
ECHO Where: "some_command" is the command whose output should be redirected 
ECHO   "filename"  is the file the output should be redirected to 
ECHO   -a    appends the output of the command to the file, 
ECHO      rather than overwriting the file 
ECHO. 
ECHO Written by Rob van der Woude 
ECHO http://www.robvanderwoude.com 
ECHO Modified by Kees Couprie 
ECHO http://kees.couprie.org 
ECHO and Andrew Cameron 

Я пытаюсь разделить выход, чтобы сохранить вывод консоли в файл, все еще имея возможность взаимодействовать с запущенной программой.

Как я могу заставить команду Tee правильно работать с моим .bat, чтобы я мог разделить вывод как на файл, так и на консоль.

+0

Хм, это работает для меня. Вы уверены, что 'mycommand.exe' выводит на stdout, а не stderr? Чтобы также захватить последнее, вам понадобится 'mycommand.exe 2> & 1 | call tee ... ' –

ответ

18

Ваша попытка вызова пакетной функции внутри канала всегда будет терпеть неудачу из-за того, как работают трубы Windows - Windows создает обе стороны канала через новые CMD-оболочки. См. https://stackoverflow.com/a/8194279/1012053 для получения дополнительной информации.

Эта версия пакетного тройника Роб ван дер Вуде не может работать для вас, потому что он использует FOR /F для чтения результатов команды - команда должна выполнить до завершения, прежде чем читать строки. Это не сработает, если вам потребуется взаимодействие с пользователем во время выполнения команды. С этой версией tee вы можете просто перенаправить вывод в файл, а затем TYPE файл по окончании. Очевидно, не то, что вы хотите.

Есть чистые пакетные трюки, которые могут приблизить вас, но я думаю, что есть еще одна проблема, которая не может быть решена с помощью чистой партии. Ваш исполняемый файл может вывести приглашение на строку без создания новой строки. Я считаю, что чистая нативная партия всегда читает целые строки (кроме случаев, когда в конце потока). Я не знаю о методе пакетной обработки для чтения символа по символу.

Незначительная коррекция - SET /P может читать частичные линии централизованного ввода, но имеет ограничение, которые не позволяют ему быть использованы для надежного решения партии тройника: Там нет никакого способа, чтобы знать наверняка, когда каждые концы линии , Он ограничен 1021 символом на «линию». Он разбивает управляющие символы с конца каждой «линии». Невозможно сказать, когда он достигнет конца входного потока.

Но есть простое решение - JScript или VBScript работает как чемпион и не требует каких-либо специальных установок. Вот гибридный JScript/пакетный скрипт, который должен работать для вас. JScript плохо написан с большим количеством возможностей для улучшения. Например, проверка ошибок отсутствует.

Я сохраняю сценарий как 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

Можно поместить все в один пакетный скрипт, как вам кажется.

@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); 
} 

Update

Для тех, кто с академическим интересом в пакетном сценарии, я отправил чистую родную пакетную версию тройника на Asynchronous native batch tee script над на DosTips. Но этот гибридный подход - мое предпочтительное решение для сценариев.

+1

+1, Ницца, только часть' Я считаю, что чистая родная партия всегда читает целые строки', это неправильно, я использую это в некоторых партиях _multithreading_ – jeb

+2

@jeb - Покажи мне больше! Я заинтригован. – dbenham

+1

Это работает отлично! Большое спасибо, я бы голосовал 5 раз, если мог. – Nick

Смежные вопросы