Displaying Windows command prompt output and redir

2019-01-01 02:33发布

问题:

How can I run a command-line application in the Windows command prompt and have the output both displayed and redirected to a file at the same time?

If, for example, I were to run the command dir > test.txt, this would redirect output to a file called test.txt without displaying the results.

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?

回答1:

I was able to find a solution/workaround of redirecting output to a file and then to the console:

dir > a.txt | type a.txt

where dir is the command which output needs to be redirected, a.txt a file where to store output.



回答2:

To expand on davor\'s answer, you can use PowerShell like this:

powershell \"dir | tee test.txt\"

If you\'re trying to redirect the output of an exe in the current directory, you need to use .\\ on the filename, eg:

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


回答3:

There\'s a Win32 port of the Unix tee command, that does exactly that. See http://unxutils.sourceforge.net/ or http://getgnuwin32.sourceforge.net/



回答4:

Check this out: wintee

No need for cygwin.

I did encounter and report some issues though.

Also you might check unxutils because it contains tee (and no need for cygwin), but beware that output EOL\'s are UNIX-like here.

Last, but not least, is if you have PowerShell, you could try Tee-Object. Type get-help tee-object in PowerShell console for more info.



回答5:

@tori3852

I found that

dir > a.txt | type a.txt

didn\'t work (first few lines of dir listing only - suspect some sort of process forking and the second part, the \'type\' command terminated before the dire listing had completed? ), so instead I used:

dir > z.txt && type z.txt

which did - sequential commands, one completes before the second starts.



回答6:

Unfortunately there is no such thing.

Windows console applications only have a single output handle. (Well, there are two STDOUT, STDERR but it doesn\'t matter here) The > redirects the output normally written to the console handle to a file handle.

If you want to have some kind of multiplexing you have to use an external application which you can divert the output to. This application then can write to a file and to the console again.



回答7:

A simple C# console application would do the trick:

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

To use this you just pipe the source command into the program and provide the path of any files you want to duplicate the output to. For example:

dir | CopyToFiles files1.txt files2.txt 

Will display the results of dir as well as store the results in both files1.txt and files2.txt.

Note that there isn\'t much (anything!) in the way of error handling above, and supporting multiple files may not actually be required.



回答8:

This works, though it\'s a bit ugly:

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

It\'s a little more flexible than some of the other solutions, in that it works statement-by-statement so you can use it to append as well. I use this quite a bit in batch files to log and display messages:

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

Yes, you could just repeat the ECHO statement (once for the screen and the second time redirecting to the logfile), but that looks just as bad and is a bit of a maintenance issue. At least this way you don\'t have to make changes to messages in two places.

Note that _ is just a short filename, so you\'ll need to make sure to delete it at the end of your batch file (if you\'re using a batch file).



回答9:

mtee is a small utility which works very well for this purpose. It\'s free, source is open, and it Just Works.

You can find it at http://www.commandline.co.uk.

Used in a batch file to display output AND create a log file simultaneously, the syntax looks like this:

    someprocess | mtee /+ mylogfile.txt

Where /+ means to append output.

This assumes that you have copied mtee into a folder which is in the PATH, of course.



回答10:

I agree with Brian Rasmussen, the unxutils port is the easiest way to do this. In the Batch Files section of his Scripting Pages Rob van der Woude provides a wealth of information on the use MS-DOS and CMD commands. I thought he might have a native solution to your problem and after digging around there I found TEE.BAT, which appears to be just that, an MS-DOS batch language implementation of tee. It is a pretty complex-looking batch file and my inclination would still be to use the unxutils port.



回答11:

I’d like to expand a bit on Saxon Druce’s excellent answer.

As stated, you can redirect the output of an executable in the current directory like so:

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

However, this only logs stdout to test.txt. It doesn’t also log stderr.

The obvious solution would be to use something like this:

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

However, this won’t work for all something.exes. Some something.exes will interpret the 2>&1 as an argument and fail. The correct solution is to instead only have apostrophes around the something.exe and it’s switches and arguments, like so:

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


回答12:

If you have cygwin in your windows environment path you can use:

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


回答13:

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

This will help to redirect both STDOUT and STDERR



回答14:

I was also looking for the same solution, after a little try, I was successfully able to achieve that in Command Prompt. Here is my solution :

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

It even captures any PAUSE command as well.



回答15:

send output to console, append to console log, delete output from current command

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


回答16:

Here\'s a sample of what I\'ve used based on one of the other answers

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

@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

This will create a log file with the current datetime and you can the console lines during the process



回答18:

I know this is a very old topic, but in previous answers there is not a full implementation of a real time Tee written in Batch. My solution below is a Batch-JScript hybrid script that use the JScript section just to get the output from the piped command, but the processing of the data is done in the Batch section. This approach have the advantage that any Batch programmer may modify this program to fit specific needs. This program also correctly process the output of CLS command produced by other Batch files, that is, it clear the screen when CLS command output is detected.

@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\");


回答19:

Something like this should do what you need?

%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


回答20:

This is a variation on a previous answer by MTS, however it adds some functionality that might be useful to others. Here is the method that I used:

  • A command is set as a variable, that can be used later throughout the code, to output to the command window and append to a log file, using set _Temp_Msg_Cmd=
    • the command has escaped redirection using the carrot ^ character so that the commands are not evaluated initially
  • A temporary file is created with a filename similar to the batch file being run called %~n0_temp.txt that uses command line parameter extension syntax %~n0 to get the name of the batch file.
  • The output is appended to a separate log file %~n0_log.txt

Here is the sequence of commands:

  1. The output and error messages are sent to the temporary file ^> %~n0_temp.txt 2^>^&1
  2. The content of the temporary file is then both:
    • appended to the logfile ^& type %~n0_temp.txt ^>^> %~n0_log.txt
    • output to the command window ^& type %~n0_temp.txt
  3. The temporary file with the message is deleted ^& del /Q /F %~n0_temp.txt

Here is the example:

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

This way then the command can simply be appended after later commands in a batch file that looks a lot cleaner:

echo test message %_Temp_Msg_Cmd%

This can be added to the end of other commands as well. As far as I can tell it will work when messages have multiple lines. For example the following command outputs two lines if there is an error message:

net use M: /D /Y %_Temp_Msg_Cmd%



回答21:

I use a batch subroutine with a \"for\" statement to get the command output one line at a time and both write that line to a file and output it to the console.

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

Following helps if you want something really seen on the screen - even if the batch file was redirected to a file. The device CON maybe used also if redirected to a file

Example:

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

Also see good redirection description: http://www.p-dd.com/chapter7-page14.html



回答23:

How do I display and redirect output to a file. Suppose if I use dos command, dir > test.txt ,this command will redirect output to file test.txt without displaying the results. how to write a command to display the output and redirect output to a file using DOS i.e., windows command prompt, not in UNIX/LINUX.

You may find these commands in biterscripting ( http://www.biterscripting.com ) useful.

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.


回答24:

This works in real time but is also kind a ugly and the performance is slow. Not well tested either:

@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


回答25:

An alternative is to tee stdout to stderr within your program:

in java:

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

Then, in your dos batchfile: java program > log.txt

The stdout will go to the logfile and the stderr (same data) will show on the console.



回答26:

Just like unix

dir | tee a.txt

does work On windows XP, it requires mksnt installed

It displayes on the promt as well as appends to the file



回答27:

I install perl on most of my machines so an answer using 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 or dir | perl tee.pl dir.bat

crude and untested.



回答28:

try this:
dir > test.txt & type test.txt