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

时间:2009-04-28 06:32:23

标签: batch-file cmd stdout tee

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

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

如何编写命令以在Windows命令提示符中将输出重定向输出显示到文件,类似于Unix上的tee命令?

33 个答案:

答案 0 :(得分:126)

要展开davor's answer,您可以像这样使用PowerShell:

powershell "dir | tee test.txt"

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

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

答案 1 :(得分:124)

我能够找到将输出重定向到文件然后到控制台的解决方案/解决方法:

dir > a.txt | type a.txt

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

答案 2 :(得分:90)

Unix tee命令的Win32端口就是这样做的。请参阅http://unxutils.sourceforge.net/http://getgnuwin32.sourceforge.net/

答案 3 :(得分:48)

检查出来:wintee

不需要cygwin。

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

你也可以检查unxutils,因为它包含tee(并且不需要cygwin),但要注意输出EOL在这里类似于UNIX。

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

答案 4 :(得分:42)

@ tori3852

我找到了

dir > a.txt | type a.txt

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

dir > z.txt && type z.txt

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

答案 5 :(得分:22)

一个简单的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());
        }
    }
}

要使用此功能,您只需将源命令传递到程序中,并提供要将输出复制到的任何文件的路径。例如:

dir | CopyToFiles files1.txt files2.txt 

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

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

答案 6 :(得分:21)

不幸的是没有这样的事情。

Windows控制台应用程序只有一个输出句柄。 (好吧,有两个STDOUTSTDERR但这里没关系。>将通常写入控制台句柄的输出重定向到文件句柄。

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

答案 7 :(得分:18)

虽然有点难看但是有效:

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

它比其他一些解决方案更灵活一点,因为它可以逐个语句地工作,因此您也可以使用它进行追加。我在批处理文件中使用了相当多的东西来记录和显示消息:

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

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

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

答案 8 :(得分:16)

mtee是一个小型实用程序,可以很好地实现此目的。它是免费的,源是开放的,它只是工作。

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

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

    someprocess | mtee /+ mylogfile.txt

其中/ +表示附加输出。

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

答案 9 :(得分:9)

我同意Brian Rasmussen的观点,unxutils端口是最简单的方法。在他Batch FilesScripting Pages部分中,Rob van der Woude提供了有关使用MS-DOS和CMD命令的大量信息。我认为他可能有一个原生的解决方案来解决你的问题,然后在那里挖掘我发现TEE.BAT,这似乎只是一个MS-DOS批处理语言实现的tee。这是一个非常复杂的批处理文件,我的倾向仍然是使用unxutils端口。

答案 10 :(得分:8)

我想对Saxon Druce的excellent answer进行一些扩展。

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

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

但是,这只会将stdout记录到test.txt。它也不会记录stderr

显而易见的解决方案是使用类似的东西:

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

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

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

答案 11 :(得分:7)

如果您在Windows环境路径中有cygwin,则可以使用:

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

答案 12 :(得分:6)

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

这将有助于重定向STDOUT和STDERR

答案 13 :(得分:4)

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

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

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

答案 14 :(得分:4)

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

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

答案 15 :(得分:3)

这样的事情应该做你需要的吗?

%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

答案 16 :(得分:3)

以下是我根据其他答案之一使用的示例

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

答案 17 :(得分:3)

我知道这是一个非常古老的话题,但在之前的答案中,并没有完全实现以批处理方式编写的实时Tee。我的解决方案是Batch-JScript混合脚本,它使用JScript部分来获取管道命令的输出,但数据处理在Batch部分完成。这种方法的优点是任何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");

答案 18 :(得分:2)

@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

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

答案 19 :(得分:2)

这是MTS对先前answer的变体,但它添加了一些可能对其他人有用的功能。这是我使用的方法:

  • 将命令设置为变量,可以在以后的整个代码中使用,输出到命令窗口并使用set _Temp_Msg_Cmd=附加到日志文件
    • 命令已使用胡萝卜^字符转义redirection,以便最初不评估命令
  • 创建一个临时文件,其文件名类似于正在运行的名为%~n0_temp.txt的批处理文件,该文件使用command line parameter extension syntax %~n0来获取批处理文件的名称。
  • 输出附加到单独的日志文件%~n0_log.txt

以下是命令序列:

  1. 输出和错误消息将发送到临时文件^> %~n0_temp.txt 2^>^&1
  2. 临时文件的内容是:
    • 附加到日志文件^& type %~n0_temp.txt ^>^> %~n0_log.txt
    • 输出到命令窗口^& type %~n0_temp.txt
  3. 删除包含邮件的临时文件^& del /Q /F %~n0_temp.txt
  4. 以下是示例:

    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%

答案 20 :(得分:1)

如果您使用的是CLI,为什么不使用FOR循环“执行”所需的任何操作:

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

有关Windows CMD的大量资源,可用于循环:https://ss64.com/nt/for_cmd.html 此处的关键是将会破坏输出的每一行的分度数(delims)设置为零。这样,它不会在默认的空白处中断。 %a是一个任意字母,但是在“ do”部分中使用了它,以便...对每一行中解析的字符进行某些处理。在这种情况下,我们可以使用与号(&&)执行第二个echo命令,以创建或附加(>>)到我们选择的文件中。在编写文件时遇到问题时,更安全地保持DO命令的顺序,我们至少至少首先将回声发送到控制台。第一个echo前面的at符号(@)禁止控制台显示echo命令本身,而是仅显示命令的结果,即在%a中显示字符。否则,您会看到:

  

驱动器[x]中的音量是Windows
驱动器[x]中的音量是Windows

更新:/ F跳过空行,唯一的解决方法是对输出进行预过滤,在每行中添加一个字符(也许通过命令find获得行号)。在CLI中解决此问题并不快捷。另外,我没有包括STDERR,因此这里也捕获了错误:

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

Redirecting Error Messages

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

答案 21 :(得分:1)

我使用带有“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

答案 22 :(得分:0)

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

    @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

答案 23 :(得分:0)

这不是另一个答案,而是对已存在的答案(例如, Displaying Windows command prompt output and redirecting it to a file 和其他

我自己发现存在一系列问题,这使得一组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 continnue...)的输出。

缺点


  1. UnxUtils 实现:

http://unxutils.sourceforge.net/

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

专业人士

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

缺点

尚未找到


  1. ss64.net 实现:

http://ss64.net/westlake/nt

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

专家

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

缺点

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

  1. ritchielawrence mtee 实现:

https://ritchielawrence.github.io/mtee

https://github.com/ritchielawrence/mtee

专业人士

缺点


因此,如果您在上述选项中选择tee实用程序实现,那么更好的选择是UnxUtilsmtee

答案 24 :(得分:0)

我刚刚找到了一种使用perl替代方法的方法,例如:

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

答案 25 :(得分:0)

我在大多数机器上安装了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

粗糙且未经测试。

答案 26 :(得分:0)

就像unix一样。

dir | tee a.txt

在Windows XP上工作,需要安装mksnt

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

答案 27 :(得分:0)

另一种方法是在程序中将stdout发送到stderr:

在java中:

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

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

stdout将转到日志文件,stderr(相同数据)将显示在控制台上。

答案 28 :(得分:0)

这是实时工作,但也有点难看,性能很慢。没有经过充分测试:

@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

答案 29 :(得分:0)

  

如何显示和重定向输出   到一个文件。假设我使用dos   命令,dir&gt; test.txt,这个命令   将输出重定向到文件test.txt   没有显示结果。如何   写一个命令来显示输出   并使用输出将输出重定向到文件   DOS即Windows命令提示符,而不是   在UNIX / LINUX中。

您可能会发现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.

答案 30 :(得分:0)

如果你想要在屏幕上看到的东西,即使批量文件被重定向到文件,也会有以下帮助。如果重定向到文件

,也可以使用设备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

答案 31 :(得分:-1)

  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. 在名为“打字稿”的文本文件中查看程序的屏幕输出

答案 32 :(得分:-3)

尝试:
    dir> test.txt并输入test.txt