14

我正在尝试使用为 bat 文件编写的tee代码,但在我的代码中实现它时遇到了麻烦。我不想使用任何第三方安装来解决 tee 问题,因为如果我在一年内格式化我的计算机并想再次运行该程序,我希望代码能够工作。

我以这种方式设置它:

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 一起正常工作,以便我可以将输出拆分到文件和控制台。

4

1 回答 1

24

由于 Windows 管道的工作方式,您在管道中调用批处理函数的尝试总是会失败 - Windows 通过新的 CMD 外壳实例化管道的两侧。有关更多信息,请参阅https://stackoverflow.com/a/8194279/1012053

批处理 tee 的 Rob van der Woude 版本可能无法为您工作,因为它使用 aFOR /F来读取命令的结果 - 该命令必须在读取任何行之前执行完成。如果您在命令执行期间需要用户交互,那将不起作用。使用该版本的 tee,您还不如简单地将输出重定向到一个文件,然后TYPE在完成后重定向到该文件。显然不是你想要的。

有纯批处理的技巧可以让你更接近,但我认为还有一个问题是纯批处理无法解决的。您的可执行文件可能会在一行上显示提示而不发出新行。我相信纯原生批处理总是读取整行(流结束时除外)。我不知道逐个字符读取的批处理方法。

轻微修正-SET /P可以读取管道输入的部分行,但它有一些限制,使其无法用于强大的批处理 tee 解决方案:无法确定每行何时结束。每“行”限制为 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);
}

更新

For anyone with an academic interest in batch scripting, I've posted a pure native batch version of tee at Asynchronous native batch tee script over at DosTips. But this hybrid approach is my preferred scripting solution.

于 2012-05-23T11:51:38.040 回答