显示Windows命令提示符输出并将其重定向到文件

如何在Windows命令提示符中运行命令行应用程序,同时显示输出并将输出重定向到文件?

例如,如果我要运行命令dir > test.txt,这将把输出重定向到一个名为test.txt的文件,而不显示结果。

我如何写一个命令来显示输出而且重定向输出到Windows命令提示符中的一个文件,类似于Unix上的tee命令?

579506 次浏览

Unix tee命令有一个Win32端口,它确实做到了这一点。参见http://unxutils.sourceforge.net/http://getgnuwin32.sourceforge.net/

不幸的是,没有这样的东西。

Windows控制台应用程序只有一个输出句柄。(嗯,有两个STDOUTSTDERR,但在这里不重要)>将通常写入控制台句柄的输出重定向到文件句柄。

如果你想要有某种多路复用,你必须使用一个外部应用程序,你可以将输出转移到它。然后,该应用程序可以再次写入文件和控制台。

一个简单的c#控制台应用程序就可以做到这一点:

using System;
using System.Collections.Generic;
using System.IO;


namespace CopyToFiles
{
class Program
{
static void Main(string[] args)
{
var buffer = new char[100];
var outputs = new List<TextWriter>();


foreach (var file in args)
outputs.Add(new StreamWriter(file));


outputs.Add(Console.Out);


int bytesRead;
do
{
bytesRead = Console.In.ReadBlock(buffer, 0, buffer.Length);
outputs.ForEach(o => o.Write(buffer, 0, bytesRead));
} while (bytesRead == buffer.Length);


outputs.ForEach(o => o.Close());
}
}
}

要使用该命令,只需将source命令导入程序,并提供要将输出复制到的任何文件的路径。例如:

dir | CopyToFiles files1.txt files2.txt

将显示dir的结果,并将结果存储在files1.txt和files2.txt中。

请注意,上面的错误处理方式并没有太多(任何东西!),实际上可能并不需要支持多个文件。

我同意Brian Rasmussen的观点,unxutils移植是最简单的方法。在他的脚本的页面批处理文件部分,Rob van der Woude提供了大量关于使用MS-DOS和CMD命令的信息。我想他可能对你的问题有一个本地的解决方案,在挖掘之后,我发现TEE.BAT,这似乎就是tee的MS-DOS批处理语言实现。这是一个看起来相当复杂的批处理文件,我仍然倾向于使用unxutils端口。

如果你想在屏幕上真正看到一些东西,下面的步骤会有所帮助——即使批处理文件被重定向到一个文件。如果重定向到一个文件,也可以使用设备CON

例子:

ECHO first line on normal stdout. maybe redirected
ECHO second line on normal stdout again. maybe redirected
ECHO third line is to ask the user. not redirected  >CON
ECHO fourth line on normal stdout again. maybe redirected

另请参见良好的重定向描述:http://www.p-dd.com/chapter7-page14.html

我能够找到一个解决方案/工作区,将输出重定向到文件然后到控制台:

dir > a.txt | type a.txt

其中dir是需要重定向输出的命令,a.txt是存储输出的文件。

如何显示和重定向输出 到一个文件。假设我使用dos dir > test.txt,执行此命令 将重定向输出到文件test.txt 不显示结果。如何 写一个命令来显示输出 并将输出重定向到文件使用 DOS,即windows命令提示符,而不是 在UNIX / LINUX。< / p >

你可能会发现biterscripting (http://www.biterscripting.com)中的这些命令很有用。

var str output
lf > $output
echo $output                            # Will show output on screen.
echo $output > "test.txt"               # Will write output to file test.txt.
system start "test.txt"                 # Will open file test.txt for viewing/editing.
@echo on


set startDate=%date%
set startTime=%time%


set /a sth=%startTime:~0,2%
set /a stm=1%startTime:~3,2% - 100
set /a sts=1%startTime:~6,2% - 100




fullprocess.bat > C:\LOGS\%startDate%_%sth%.%stm%.%sts%.LOG | fullprocess.bat

这将创建一个包含当前日期时间的日志文件,您可以在此过程中设置控制台行

@tori3852

我发现

dir > a.txt | type a.txt

没有工作(仅dir列表的前几行-怀疑某种进程分叉和第二部分,'type'命令在可怕的列表完成之前终止?), 所以我使用:

dir > z.txt && type z.txt

顺序命令,一个在第二个开始之前完成。

这是可行的,尽管它有点丑陋:

dir >_ && type _ && type _ > a.txt

它比其他一些解决方案更灵活一些,因为它是一条一条地工作的,所以您也可以使用它来追加。我在批处理文件中经常使用这种方法来记录和显示消息:

ECHO Print line to screen and log to file.  >_ && type _ && type _ >> logfile.txt

是的,您可以只重复ECHO语句(一次用于屏幕,第二次重定向到日志文件),但这看起来同样糟糕,并且存在一些维护问题。至少这样您就不必在两个地方对消息进行更改。

注意_只是一个简短的文件名,所以你需要确保在批处理文件的末尾删除它(如果你使用的是批处理文件)。

Mtee是一个小型实用程序,它非常适合这个目的。它是免费的,源代码是开放的,而且很好用。

你可以在http://www.commandline.co.uk找到它。

在批处理文件中用于显示输出并同时创建日志文件,语法如下所示:

    someprocess | mtee /+ mylogfile.txt

其中/+表示附加输出。

当然,这假设您已经将mtee复制到PATH中的文件夹中。

dir 1>a.txt 2>&1 | type a.txt

这将有助于重定向STDOUT和STDERR

下面是我使用的一个基于其他答案的例子

@echo off
REM SOME CODE
set __ERROR_LOG=c:\errors.txt
REM set __IPADDRESS=x.x.x.x


REM Test a variable
if not defined __IPADDRESS (
REM Call function with some data and terminate
call :TEE %DATE%,%TIME%,IP ADDRESS IS NOT DEFINED
goto :EOF
)


REM If test happens to be successful, TEE out a message and end script.
call :TEE Script Ended Successful
goto :EOF




REM THE TEE FUNCTION
:TEE
for /f "tokens=*" %%Z in ("%*") do (
>  CON ECHO.%%Z
>> "%__ERROR_LOG%" ECHO.%%Z
goto :EOF
)

看看这个:wintee

不需要cygwin。

不过,我确实遇到并报告了一些问题。

你也可以检查unxutils,因为它包含tee(不需要cygwin),但注意这里的输出EOL是类unix的。

最后,但并非最不重要的是,如果你有PowerShell,你可以尝试Tee-Object。在PowerShell控制台中键入get-help tee-object以获取更多信息。

这是实时工作,但也是一种丑陋和性能缓慢。也没有经过很好的测试:

@echo off
cls
SET MYCOMMAND=dir /B
ECHO File called 'test.bat' > out.txt
for /f "usebackq delims=" %%I in (`%MYCOMMAND%`) do (
ECHO %%I
ECHO %%I >> out.txt
)
pause

另一种选择是在程序中tee stdout到stderr:

在java中:

System.setOut(new PrintStream(new TeeOutputStream(System.out, System.err)));

然后,在你的dos批处理文件:java program > log.txt

标准输出将转到日志文件,标准derr(相同的数据)将显示在控制台上。

就像unix一样。

dir | tee a.txt

在windows XP上,它需要安装mksnt

它显示在提示符上,并附加到文件中。

我知道这是一个非常古老的话题,但在之前的回答中,并没有批量编写实时Tee的完整实现。下面我的解决方案是一个Batch-JScript混合脚本,它使用JScript部分来获得管道命令的输出,但是数据的处理是在Batch部分中完成的。这种方法的优点是任何批处理程序员都可以修改这个程序以适应特定的需要。该程序还正确地处理其他批处理文件产生的CLS命令输出,即当检测到CLS命令输出时清除屏幕。

@if (@CodeSection == @Batch) @then




@echo off
setlocal EnableDelayedExpansion


rem APATee.bat: Asynchronous (real time) Tee program, Batch-JScript hybrid version
rem Antonio Perez Ayala


rem The advantage of this program is that the data management is written in Batch code,
rem so any Batch programmer may modify it to fit their own needs.
rem As an example of this feature, CLS command is correctly managed


if "%~1" equ "" (
echo Duplicate the Stdout output of a command in the screen and a disk file
echo/
echo anyCommand ^| APATee teeFile.txt [/A]
echo/
echo If /A switch is given, anyCommand output is *appended* to teeFile.txt
goto :EOF
)


if "%2" equ ":TeeProcess" goto TeeProcess


rem Get the output of CLS command
for /F %%a in ('cls') do set "cls=%%a"


rem If /A switch is not provided, delete the file that receives Tee output
if /I "%~2" neq "/A" if exist %1 del %1


rem Create the semaphore-signal file and start the asynchronous Tee process
echo X > Flag.out
if exist Flag.in del Flag.in
Cscript //nologo //E:JScript "%~F0" | "%~F0" %1 :TeeProcess
del Flag.out
goto :EOF


:TeeProcess
rem Wait for "Data Available" signal
if not exist Flag.in goto TeeProcess
rem Read the line sent by JScript section
set line=
set /P line=
rem Set "Data Read" acknowledgement
ren Flag.in Flag.out
rem Check for the standard "End Of piped File" mark
if "!line!" equ ":_EOF_:" exit /B
rem Correctly manage CLS command
if "!line:~0,1!" equ "!cls!" (
cls
set "line=!line:~1!"
)
rem Duplicate the line in Stdout and the Tee output file
echo(!line!
echo(!line!>> %1
goto TeeProcess




@end




// JScript section


var fso = new ActiveXObject("Scripting.FileSystemObject");
// Process all lines of Stdin
while ( ! WScript.Stdin.AtEndOfStream ) {
// Read the next line from Stdin
var line = WScript.Stdin.ReadLine();
// Wait for "Data Read" acknowledgement
while ( ! fso.FileExists("Flag.out") ) {
WScript.Sleep(10);
}
// Send the line to Batch section
WScript.Stdout.WriteLine(line);
// Set "Data Available" signal
fso.MoveFile("Flag.out", "Flag.in");
}
// Wait for last "Data Read" acknowledgement
while ( ! fso.FileExists("Flag.out") ) {
WScript.Sleep(10);
}
// Send the standard "End Of piped File" mark
WScript.Stdout.WriteLine(":_EOF_:");
fso.MoveFile("Flag.out", "Flag.in");

要扩展达沃的回答,你可以像这样使用PowerShell:

powershell "dir | tee test.txt"

如果你试图重定向当前目录中的exe的输出,你需要在文件名上使用.\,例如:

powershell ".\something.exe | tee test.txt"

我在我的大多数机器上安装perl,所以答案使用perl: tee.pl

my $file = shift || "tee.dat";
open $output, ">", $file or die "unable to open $file as output: $!";
while(<STDIN>)
{
print $_;
print $output $_;
}
close $output;

dir | perl tee.pl 或 Dir | perl tee.pl Dir .bat

粗糙且未经检验。

我使用带有“for”语句的批处理子例程来一次一行地获取命令输出,并将该行写入文件并输出到控制台。

@echo off
set logfile=test.log


call :ExecuteAndTee dir C:\Program Files


Exit /B 0


:ExecuteAndTee
setlocal enabledelayedexpansion
echo Executing '%*'
for /f "delims=" %%a in ('%* 2^>^&1') do (echo.%%a & echo.%%a>>%logfile%)
endlocal
Exit /B 0

如果你的windows环境路径中有cygwin,你可以使用:

 dir > a.txt | tail -f a.txt

我也在寻找同样的解决方案,经过一些尝试,我成功地在命令提示符中实现了这一点。以下是我的解决方案:

@Echo off
for /f "Delims=" %%a IN (xyz.bat) do (
%%a > _ && type _ && type _ >> log.txt
)
@Echo on

它甚至还可以捕获任何PAUSE命令。

发送输出到控制台,附加到控制台日志,从当前命令删除输出

dir  >> usb-create.1 && type usb-create.1 >> usb-create.log | type usb-create.1 && del usb-create.1

这是MTS之前回答的一个变体,但是它增加了一些可能对其他人有用的功能。下面是我使用的方法:

    命令被设置为一个变量,以后可以在整个代码中使用,使用set _Temp_Msg_Cmd=输出到命令窗口并附加到日志文件中
    • 命令使用carrot ^字符转义了重定向,这样命令就不会被初始化
    • 李< / ul > < / >
    • 创建一个临时文件,其文件名与正在运行的批处理文件类似,称为%~n0_temp.txt,该文件使用命令行参数扩展语法 %~n0获取批处理文件的名称。
    • 输出被追加到一个单独的日志文件%~n0_log.txt

    下面是命令的顺序:

    1. 输出和错误消息被发送到临时文件^> %~n0_temp.txt 2^>^&1
    2. 临时文件的内容是:
      • 附加到日志文件^& type %~n0_temp.txt ^>^> %~n0_log.txt
      • 输出到命令窗口^& type %~n0_temp.txt
      • 李< / ul > < / >
      • 带有消息的临时文件^& del /Q /F %~n0_temp.txt被删除

    下面是例子:

    set _Temp_Msg_Cmd= ^> %~n0_temp.txt 2^>^&1 ^& type %~n0_temp.txt ^>^> %~n0_log.txt ^& type %~n0_temp.txt ^& del /Q /F %~n0_temp.txt

    这样,命令就可以简单地附加在批处理文件中后面的命令之后,看起来更干净:

    echo test message %_Temp_Msg_Cmd%

    这也可以添加到其他命令的末尾。据我所知,当消息有多行时,它将工作。例如,如果有错误消息,以下命令将输出两行:

    net use M: /D /Y %_Temp_Msg_Cmd%

这样的东西能满足你的需要吗?

%DATE%_%TIME% > c:\a.txt & type c:\a.txt
ipconfig >> c:\a.txt & type c:\a.txt
ping localhost >> c:\a.txt & type c:\a.txt
pause

我想扩展一下Saxon Druce的优秀的答案

如上所述,您可以重定向当前目录中的可执行文件的输出,如下所示:

powershell ".\something.exe | tee test.txt"

然而,这只记录stdouttest.txt。它也不会记录stderr

最明显的解决方法是使用如下内容:

powershell ".\something.exe 2>&1 | tee test.txt"

然而,这并不适用于所有的__abc。一些__abc0会将2>&1解释为参数并失败。正确的解决方案是在something.exe及其开关和参数周围只使用撇号,如下所示:

powershell ".\something.exe --switch1 --switch2 … arg1 arg2 …" 2^>^&1 ^| tee test.txt

但是请注意,在这种情况下,您必须转义特殊的cmd-shell字符">&|"有"^"每一个都只能被powershell解释。

如果你在CLI中,为什么不用FOR循环来“DO”你想做的事情:

for /F "delims=" %a in ('dir') do @echo %a && echo %a >> output.txt

伟大的资源在Windows CMD循环:https://ss64.com/nt/for_cmd.html 这里的关键是设置delimeter (delims),这将分解输出的每一行。这样它就不会在默认的空白状态下中断。%a是一个任意的字母,但是它被用在“do”部分,嗯…对每行解析的字符进行处理。在这种情况下,我们可以使用&号(&&)来执行第二个echo命令来创建或追加(>>)到我们选择的文件。保持DO命令的这个顺序更安全,以防在写入文件时出现问题,我们至少会先获得对控制台的回显。第一个回显前面的at符号(@)抑制控制台显示echo命令本身,而只是显示命令的结果,即显示%a中的字符。否则你会看到:

echo驱动器[x]中的卷是Windows
驱动器[x]中的卷是Windows

UPDATE: /F跳过空行,唯一的修复是预过滤输出,向每一行添加一个字符(可能通过命令find使用行号)。在CLI中解决这个问题既不快速也不漂亮。此外,我没有包括STDERR,所以这里捕获错误:

for /F "delims=" %a in ('dir 2^>^&1') do @echo %a & echo %a >> output.txt

重定向错误消息

插入符号(^)用于转义后面的符号,因为命令是一个正在被解释的字符串,而不是直接在命令行中输入它。

另一种变化是分割管道,然后根据需要重新定向输出。

    @echo off
for /f "tokens=1,* delims=:" %%P in ('findstr /n "^"') do (
echo(%%Q
echo(%%Q>&3
)
@exit/b %errorlevel%

将上述内容保存到.bat文件中。它还将文件流1上的文本输出分割到文件流3,您可以根据需要重定向。在下面的例子中,我将上面的脚本称为splitPipe.bat…

    dir | splitPipe.bat  1>con  2>&1  3>my_stdout.log


splitPipe.bat 2>nul < somefile.txt
  1. https://cygwin.com/install
  2. 点击“setup- x86_exe”链接
  3. 运行安装程序
  4. 在~第二页,选择一个“镜像”来下载(我找了一个。edu域名)
  5. 我同意了标准选项
  6. Cygwin快速完成安装
  7. 打开cmd
  8. 输入c:\cygwin64\bin\script.exe并输入
  9. 输入cmd并输入
  10. 运行程序
  11. 输入exit并进入(退出Cygwin的cmd.exe)
  12. 输入exit并进入(退出Cygwin的script.exe)
  13. 在名为“typescript”的文本文件中查看程序的屏幕输出
我刚刚找到了一种方法来使用perl作为替代,例如:

CMD1 | perl -ne "print $_; print STDERR $_;" 2> OUTPUT.TEE < / p >

这不是另一个答案,而是对已经存在的答案的概述和澄清 显示Windows命令提示符输出,并将其重定向到一个文件 和其他< / p >

我自己发现有一组问题,使得一组tee实现在Windows中不可靠(在我的情况下为Windows 7)。

我需要特别使用tee实现,因为已经使用了自重定向的批处理脚本:

@echo off


setlocal




... some conditions here ..


rem the redirection
"%COMSPEC%" /C call %0 %* 2>&1 | "<path_to_tee_utililty>" ".log\<log_file_name_with_date_and_time>.%~nx0.log"
exit /b


:IMPL
... here the rest of script ...

如果与tee实用程序一起使用,脚本和对脚本内一些实用程序的调用可能会中断输出。


  1. gnuwin32实现:

http://gnuwin32.sourceforge.net/packages/coreutils.htm

优点:

  • 正确地处理标准输出和控制台进度条,其中\r字符被大量使用。

缺点:

  • 使控制台进度条仅在日志文件中绘制,但在控制台窗口中没有复制或可见。
  • 抛出多个错误消息Cwrite error: No such file or directory,因为cmd解释器似乎过早地关闭了管道/stdout,并且在那之后不能自我关闭(垃圾邮件直到终止)。
  • 不复制/打印控制台窗口中pause命令(Press any key to continue...)的输出。

  1. wintee实现:

https://code.google.com/archive/p/wintee/

https://github.com/rbuhl/wintee

优点:

  • 在控制台窗口和日志文件(多次打印)中显示控制台进度条。
  • 复制/打印控制台窗口中pause命令(Press any key to continue...)的输出。

缺点:


  1. 的UnxUtils实现:

http://unxutils.sourceforge.net/

https://sourceforge.net/projects/unxutils/files/unxutils/current/

优点

  • 在控制台窗口和日志文件(多次打印)中显示控制台进度条。
  • 正确处理\r字符。
  • 复制/打印控制台窗口中pause命令(Press any key to continue...)的输出。

缺点

尚未发现


  1. ss64.net实现:

http://ss64.net/westlake/nt

http://ss64.net/westlake/nt/tee.zip

优点:

  • 在控制台窗口和日志文件(多次打印)中显示控制台进度条。

缺点:

  • 错误地处理\r字符,输出是混合和混乱的
  • 由于某种原因,在按下键后会在控制台窗口中复制/打印pause命令(Press any key to continue...)的输出。

  1. ritchielawrence mtee实现:

< a href = " https://ritchielawrence.github。Io /mtee" rel="nofollow noreferrer">https://ritchielawrence.github.io/mtee

https://github.com/ritchielawrence/mtee

优点

缺点


因此,如果你在上述两个工具中选择tee实用程序实现,那么更好的选择是UnxUtilsmtee


如果你正在寻找一个更好的实现,具有更多的功能和更少的问题,那么你可以使用callf实用程序:
https://github.com/andry81/contools/blob/trunk/Utilities/src/callf/help.tpl < / p >

你可以运行而不是:

call test.bat | mtee /E 1.log

这样的:

callf.exe /ret-child-exit /tee-stdout 1.log /tee-stdout-dup 1 "" "cmd.exe /c call test.bat"

它更好,因为它可以将stdoutstderr分开进行管道连接,甚至可以使用命名管道在具有管理员特权隔离的进程之间进行管道连接。