繁体   English   中英

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

[英]Displaying Windows command prompt output and redirecting it to a file

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

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

How could I write a command to display the output and redirect output to a file in the Windows command prompt, similar to the tee command on Unix?

要扩展davor 的答案,您可以像这样使用 PowerShell:

powershell "dir | tee test.txt"

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

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

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

dir > a.txt | type a.txt

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

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

看看这个:温蒂

不需要cygwin。

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

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

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

@ tori3852

我找到

dir > a.txt | type a.txt

没有工作(仅列出目录的前几行 - 怀疑某种进程分叉,第二部分,“类型”命令在可怕的列表完成之前终止?),所以我使用:

dir > z.txt && type z.txt

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

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

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

要使用它,您只需将源命令通过管道传输到程序中,并提供要将输出复制到的任何文件的路径。 例如:

dir | CopyToFiles files1.txt files2.txt 

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

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

这有效,虽然它有点难看:

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

它比其他一些解决方案更灵活,因为它逐个语句工作,因此您也可以使用它来附加。 我在批处理文件中经常使用它来记录和显示消息:

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

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

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

我想扩展一下 Saxon Druce 的出色回答

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

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

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

显而易见的解决方案是使用这样的东西:

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

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

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

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

mtee 是一个小型实用程序,非常适合用于此目的。 它是免费的,源代码是开放的,并且可以正常工作。

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

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

    someprocess | mtee /+ mylogfile.txt

其中 /+ 表示追加输出。

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

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

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

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

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

这将有助于重定向 STDOUT 和 STDERR

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

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

@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

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

%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

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

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

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

  • 命令被设置为一个变量,稍后可以在整个代码中使用,使用set _Temp_Msg_Cmd=输出到命令窗口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%

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

我自己发现有一组问题导致一组 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 解释器似乎过早关闭管道/标准输出,之后无法自行关闭(垃圾邮件直到终止)。
  • 不复制/打印控制台窗口中pause命令( Press any key to continue... )的输出。

  1. 温蒂实施

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字符,输出混杂和混乱
  • 出于某种原因,在Press any key to continnue...在控制台窗口中复制/打印pause命令( Press any key to continnue... )的输出。

  1. ritchielawrence mtee实现:

https://ritchielawrence.github.io/mtee

https://github.com/ritchielawrence/mtee

优点

缺点


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

就像unix一样。

dir | tee a.txt

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

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

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

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

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

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

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

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

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

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

重定向错误消息

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

如果您希望在屏幕上真正看到某些内容,以下内容会有所帮助 - 即使批处理文件已重定向到文件。 如果重定向到文件,也可以使用设备 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

这可以实时工作,但也有点丑陋,而且性能很慢。 也没有经过很好的测试:

@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

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

在 Java 中:

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

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

标准输出将进入日志文件,标准错误(相同数据)将显示在控制台上。

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

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

粗糙和未经测试。

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

    @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

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

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

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

尝试这个:
目录> test.txt并输入test.txt

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM