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


371

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

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

我怎么能写一个命令来显示输出,并在Windows命令输出重定向到文件的提示,类似tee的Unix命令?


63
并且,请不要再将其称为MSDOS!cmd.exe和braindead command.com之间的相似之处很小,而且越来越小。
paxdiablo


如果有人有一个控制台应用程序可加载输出文本的dll,则这些都不起作用。主应用程序文本将重定向到文件,但dll的输出未重定向,并继续显示在控制台窗口中。我没有找到从dll捕获文本的方法。
布赖恩·雷纳德

1
人们仍然可以仅将其管道传输到文件中并在该文件上使用tail(stackoverflow.com/questions/187587/…
x29a 2014年

如果我使用命令行实用程序并且想要将输出重定向到与屏幕上显示的格式完全相同的格式,该怎么办,我使用youtube-dl提取链接,并且可以将输出重定向到txt文件,但其格式未设置为您将在提示符下进入提示,在文件中单行显示。
beastboy

Answers:


153

要扩展davor的答案,您可以使用PowerShell,如下所示:

powershell "dir | tee test.txt"

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

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

8
这是最接近的答案:它适用于默认安装,因为大多数计算机(尤其是服务器)已经安装了PS。
Stoleg 2014年

1
这是最好的答案!简单和“开箱即用”的作品
Josh Werts

3
喜欢它:)无论如何{powershell“ ping -n 10 localhost | tee test.txt”}会更好地演示在tee上发生的事情
grenix

4
请注意,dir在powershell中是一个别名,Get-ChildItem与cmd的内部dir命令不同。如果需要powershell "cmd /c dir | tee test.txt"cmd内部版本,则需要
phuclv

8
要查看所有输出,请不要忘记使用来将STDERR重定向到STDOUT 2>&1,例如node 2>&1 | tee debug_log.txt
Zhe Hu

132

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

dir > a.txt | type a.txt

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


100
这满足了答案,但是在dir命令完成之后而不是在数据生成时输出数据。
利里菲尔

10
它将起作用,但是如果命令等待stdin的输入,您将陷入困境。
Vitim.us

5
我喜欢这个简单的答案!我发现,&而不是|需要用于一些命令的输出,类似ping7z.exe
韦斯拉尔森

不适用于交互式命令而不是dir。范例:chkdsk /f c: > c:\Temp.txt | c:\Temp.txt。系统报告文件被另一个进程锁定。
Sopalajo de Arrierez '16

4
@lii re:handle output to stderr-添加2>&1重定向,如下所示:dir 2>&1 > a.txt & type a.txt并且您应该将stderr与stdout混合在一起。
Jesse Chisholm

97

Unix tee命令有一个Win32端口,可以做到这一点。请参阅http://unxutils.sourceforge.net/http://getgnuwin32.sourceforge.net/


17
该链接指向Unix命令tee的Windows实现,因此在Windows上也可以使用。
Brian Rasmussen

3
是的,投票赞成答案和评论。实际上,我更喜欢CygWin,因为它具有所有功能,但有些人更喜欢他们可以选择的非DLL工具。
paxdiablo

3
GnuWin32项目还移植了许多Unix实用程序,请参见gnuwin32.sourceforge.net 。
VladV

2
UnxUtils的最新更新时间为2003年。GnuWin32是最新的。
quack quixote 2010年

9
如果你和我一样,在努力寻找的GnuWin32的tee包,你会发现在它gnuwin32.sourceforge.net/packages/coreutils.htm
Nigel Touch

49

检查一下:wintee

不需要cygwin。

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

另外,您可能会检查unxutils,因为它包含tee(不需要cygwin),但是请注意,此处输出的EOL与UNIX类似。

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


4
为什么要投反对票?这里95%的答复有一个共同点:仅在初始命令完成后才重定向输出:阅读注释。UNIX实用程序tee实时输出。wtee具有相同的功能。如果您不介意这些错误,那将会很好。
达沃·乔西波维奇2012年

那是对我唯一有效的解决方案,没有Powershell> 4.0。竖起大拇指!
亚历克斯(Alex)

46

@ tori3852

我找到

dir > a.txt | type a.txt

不起作用(仅目录列表的前几行-怀疑某种过程分叉,而第二部分,“类型”命令在可怕列表完成之前终止了?),所以我改用:

dir > z.txt && type z.txt

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


17
如果您想确保即使命令失败也要执行命令,则应使用&代替。当命令中存在某种形式的错误并且您仍然希望在控制台上查看日志文件时,这很有用。请参阅Microsoft对此的文章。但是,这具有被设置为错误级别(将为0)的问题。&&typedir%errorlevel%type
ADTC

25

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

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

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


3
tee在* nix上也是一个单独的应用程序,而不是在外壳上进行某些重定向
phuclv

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中。

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


5
嗯,免费下载tee / cygwin还是用我来之不易的现金购买MSVS,像这样的小程序?这是一个艰难的过程:-)
paxdiablo

19
您不需要Visual Studio进行编译,命令行工具实际上是免费的。只是谷歌“。NETSDK下载”的链接(直接链接似乎改变,但谷歌似乎总是可以)。
克里斯2009年

13
Visual Studio Express也是免费的,但我仍将使用tee来实现。
Brian Rasmussen

7
cygwin很难安装。支持您,因为这就是我想要的。
Samaursa

1
我认为这不会同时输出到控制台和文件吗?
mjaggard

20

这很有效,尽管有点难看:

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

它比其他一些解决方案灵活一些,因为它可以按语句运行,因此您也可以使用它来追加。我在批处理文件中经常使用此日志来记录和显示消息:

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

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

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


2
这仅在您希望在进程运行后显示内容时才有用。这不是一个很难解决的问题。
Christopher Painter

1
是的,我想这解决了与原始海报要求的问题稍有不同的问题。
MTS

1
+1这就是我一直这样做的方式。我认为这是对原始问题的正确答案,应标记为正确答案。就像@MTS所暗示的那样,诀窍是您实际上写入了两个文件:每个命令/行都会创建一个文件(因此每次都覆盖一个“>”,然后在屏幕上键入该行(键入),最后再次键入它,并将其输出(很长的APPENDING)重定向到带有“ >>”的日志文件。尽管我喜欢简单的“ ”临时文件,但这就是我多年来所做的。我总是做过“ tmp.txt”或类似的东西。是的,然后将其删除。
eduncan911

这是一个很好的方法,但是我遇到了一些无法捕获的错误的问题。但是,将type命令放在单独的行中(在子例程中)可以解决该问题。
内特·库克

正是我需要的应用程序。
艾伦

16

mtee是一个小型工具,可以很好地实现此目的。它是免费的,源是开放的,并且可以正常工作。

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

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

    someprocess | mtee /+ mylogfile.txt

/ +表示附加输出。

假定您已经将mtee复制到了PATH中的文件夹中。


1
这似乎要等到输出完成后再输出到文件或控制台。
mellamokb

14

我想对撒克逊·德鲁斯的出色回答做些补充。

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

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

但是,这仅记录stdouttest.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

我在Windows 10上构建pyqt5.7时尝试了此操作,它相当缓慢,控制台输出不是实时的,也许是缓冲的?日志文件虽然看起来正确
Shuman

3
所有这些都是完全错误的。对我来说根本不起作用。最后一个命令给出'tee' is not recognized as an internal or external command的原因很明显。使用2>&1内部cmd线时,任何输出到stderr的命令都会导致Powershell错误。
Pavel P

可能是对PowerShell Tee-Object cmdlet的引用-technet.microsoft.com/en-us/library/ee177014.aspx
Bernd

9

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


那个tee.bat看起来不错。希望OP对此进行检查。
杰伊

10
请注意,命令完成后,将使用TEE.BAT进行输出,就像附近发布的“ dir> a.txt | type a.txt”示例一样。
adzm 2010年


7

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

这将有助于重定向STDOUT和STDERR


这行不通。我尝试使用它来启动JBoss run.bat,它在启动过程中阻塞并且服务器冻结。这种方法有问题...
djangofan 2012年

@raja ashok,对我不起作用。我试过python.exe 1> file.txt 2>&1 | file.txt的类型

4

我知道这是一个非常古老的话题,但是在以前的答案中,并没有完整实现用Batch编写的实时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");

有什么办法可以捕获stderr输出吗?我有一个烦人的exe,可以在标准错误流上输出所有内容(即,为了正常输出到文件,您可以这样做file.exe 2>output.txt
Mark Deven

我想到了。你可以用它做file.exe 2>&1|tee.bat的在这里找到:superuser.com/questions/452763/...
马克·戴文

4

我也在寻找相同的解决方案,经过一番尝试,我成功地在Command Prompt中实现了该解决方案。这是我的解决方案:

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

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


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
)

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

几乎可以,但不会同时显示-如果您的任务运行时间较长,那么很长一段时间都不会获得任何结果。
JustAMartin

3

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

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

8
想要解释这里发生了什么?
John Demetriou 2015年

2

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

  • 将命令设置为变量,可在以后的代码中使用该命令,以使用以下命令输出到命令窗口并附加到日志文件 set _Temp_Msg_Cmd=
    • 命令逃脱重定向使用胡萝卜^字符,使得命令不初步评价
  • 使用与运行的批处理文件类似的文件名创建一个临时文件,该文件名%~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
  3. 带有消息的临时文件被删除 ^& 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%


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

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


11
你不是用这个两次调用同一个程序吗?
elcool 2012年

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

尝试从命令捕获输出时(IE将其放在for中),我做同样的事情,但是我只是调用我的标准子函数以回显屏幕并写入日志,因为我在整个脚本中都使用了它来代替使用echo 。不知道为什么会受到别人的反对,所以我赞成。
Ben Personick

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中显示字符。

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

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

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

重定向错误消息

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


1

就像unix一样。

dir | tee a.txt

在Windows XP上可以运行,需要mksnt安装。

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


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


0

如何显示输出并将其重定向到文件。假设如果我使用dos命令dir> 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.

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

6
不,它不是实时的,它会等到%MYCOMMAND%完成并在许多情况下失败。它会跳过空行,行开始与;失败,如内容<space>/<TAB>ONOFF/?。但是其余的有时可能会起作用:-)
jeb 2012年

0

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

在Java中:

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

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

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


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;

目录 perl tee.pl或目录| perl tee.pl目录

原始且未经测试。


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

-1
  1. https://cygwin.com/install
  2. 单击“ setup-x86_.exe”的链接
  3. 运行安装程序
  4. 在〜第2页上,选择要下载的“镜像”(我在寻找.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”的文本文件中查看程序的屏幕输出
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.