对 .bat 文件使用自定义 Tee 命令 [英] Using a custom Tee command for .bat file

查看:24
本文介绍了对 .bat 文件使用自定义 Tee 命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to use the tee code written for a bat file but am having trouble implementing it in my code. I don't want to use any third party installs to solve the tee problem as I want the code to work if I format my computer in a year and want to run the program again.

我以这种方式设置:

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

我尝试过使用单独的 .bat 文件并尝试将其作为函数(首选)包含在原始 .bat 中,但无济于事:

I've tried with a seperate .bat file and tried including as a function (preffered) in the original .bat to no avail with:

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

我正在尝试拆分输出,这样我就可以将控制台输出保存到一个文件中,同时仍然能够与正在运行的程序进行交互.

I am trying to split the output so I can save the console output to a file while still being able to interact with the program that is running.

如何让 Tee 命令与我的 .bat 一起正常工作,以便我可以将输出拆分为文件和控制台.

推荐答案

由于 Windows 管道的工作方式,您在管道内调用批处理函数的尝试将始终失败 - Windows 通过新的 CMD 外壳实例化管道的两侧.请参阅https://stackoverflow.com/a/8194279/1012053了解详情.

Your attempt to call a batch function within a pipe will always fail because of how Windows pipes work - Windows instantiates both sides of the pipe via new CMD shells. See https://stackoverflow.com/a/8194279/1012053 for more info.

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

That Rob van der Woude version of a batch tee cannot possibly work for you because it uses a FOR /F to read the results of a command - the command must execute to completion before any lines are read. That won't work if you need user interaction during the execution of the command. With that version of tee you might as well simply redirect output to a file and then TYPE the file when finished. Obviously not what you want.

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

There are pure batch tricks that can get you closer, but I think there is still one problem that can't be solved with pure batch. Your executable may put a prompt on a line without issuing a new line. I believe pure native batch always reads entire lines (except when at end of stream). I'm not aware of a batch method to read character by character.

轻微修正 - SET/P 可以读取管道输入的部分行,但它有一些限制,阻止它被用于强大的批处理三通解决方案:无法确定每条线路何时结束.每行"限制为 1021 个字符.它从每个行"的末尾去除控制字符.无法判断何时到达输入流的末尾.

Slight correction - SET /P can read partial lines of piped input, but it has limitations that prevent it from being used for a robust batch tee solution: There is no way to know for sure when each line ends. It is limited to 1021 characters per "line". It strips control characters from the end of each "line". There is no way to tell when it has reached the end of the input stream.

但是有一个简单的解决方案 - JScript 或 VBScript 就像冠军一样工作,并且不需要任何特殊安装.这是一个应该适合您的混合 JScript/批处理脚本.JScript 写得不好,还有很大的改进空间.例如,没有错误检查.

But there is a simple solution - JScript or VBScript works like a champ, and doesn't require any special installs. Here is a hybrid JScript/batch script that should work for you. The JScript is poorly written with lots of room for improvement. For example, there is no error checking.

我将脚本保存为 tee.bat.第一个必需参数指定要写入的文件的名称.默认情况下,如果该文件已经存在,则会被覆盖.如果提供了第二个参数(值无关紧要),则将输出附加到文件中.

I save the script as tee.bat. The first required argument specifies the name of the file to write to. By default, the file is over-written if it already exists. If a second argument is provided (value doesn't matter), then the output is appended to the file instead.

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

用法与您期望的非常相似.

Usage is pretty much like you would expect.

command.exe | tee.bat output.txt 1

最后一个参数强制追加模式.它可以是除 1 之外的任何值

The last 1 argument forces append mode. It could be any value besides 1

可以按照您的喜好将所有内容放入一个批处理脚本中.

It is possible to put everything in one batch script as you seem to prefer.

@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 脚本 在 DosTips 上.但这种混合方法是我首选的脚本解决方案.

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.

这篇关于对 .bat 文件使用自定义 Tee 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆