446

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?

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • 74
    And please stop calling it MSDOS! The similarities between cmd.exe and that braindead command.com are minuscule, and getting smaller. – paxdiablo Apr 28 '09 at 07:06
  • 5
    possible duplicate of [How do I echo and send console output to a file in a bat script?](http://stackoverflow.com/questions/503846/how-do-i-echo-and-send-console-output-to-a-file-in-a-bat-script) – Joshua Drake Sep 19 '13 at 15:26
  • None of these work if one has a console application that loads a dll that outputs text. The main application text gets redirected to a file but the output from the dll does not and continues to be displayed in the console window. I have found NO way to capture the text from the dll. – Brian Reinhold Sep 25 '13 at 19:30
  • 2
    one could still just pipe into a file and use tail (http://stackoverflow.com/questions/187587/looking-for-a-windows-equivalent-of-the-unix-tail-command) on that file – x29a Mar 19 '14 at 12:36
  • What if i am using a command line utility and want to redirect the output to a file in the exact same format as displayed on screen i used youtube-dl to extract links and could redirect the output to a txt file , but its not formatted as you will get in the prompt , in the file its coming as single line. – beastboy Sep 14 '19 at 13:49

32 Answers32

208

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"
Community
  • 1
  • 1
Saxon Druce
  • 17,406
  • 5
  • 50
  • 71
  • 12
    This is the most close answer: it works on default install, as PS is already there on most machines and, especially, servers. – Stoleg Feb 14 '14 at 12:58
  • 1
    This is the best answer! Simple and works "out of the box" – Josh Werts Jan 16 '17 at 15:58
  • It works, but the file will not contain all the output – Ionut Mar 31 '17 at 20:13
  • 5
    LIKE IT :) anyhow {powershell "ping -n 10 localhost | tee test.txt"} would demonstrate better whats going on on the tee party – grenix May 22 '17 at 11:08
  • 6
    note that `dir` in powershell is an alias to `Get-ChildItem` which is not like cmd's internal `dir` command. You need `powershell "cmd /c dir | tee test.txt"` if you want the cmd internal version – phuclv Jun 03 '17 at 02:36
  • 12
    to see all the output, don't forget to redirect STDERR to STDOUT with `2>&1`, for example `node 2>&1 | tee debug_log.txt` – Zhe Hu Jul 24 '17 at 13:35
  • But you lose the text color on console output. – dehinrsu Dec 06 '17 at 10:16
  • Is is very useful command, we we want to have everything, we need 2>&1 – R.F May 17 '19 at 20:58
  • 3
    Consider adding '-Append' so the log file doesn't get truncated each command start. For example `powershell "node server.js 2>&1 | tee -Append app.log"` – Edi Jun 05 '19 at 07:49
  • 2
    With `2>&1` any stderr output will cause a "NativeCommandError" to be displayed, intermixed with the actual output. To prevent that use `powershell ".\something.exe 2>&1 | foreach {\"$_\"} | tee test.txt"`. This converts any error records to plain text before sending it to `tee`. – zett42 Apr 23 '20 at 11:48
  • This is not writing to a file in windows 10 – Chaminda Bandara Aug 25 '21 at 17:22
  • @alexei In my experience: `powershell "ping -n 10 localhost | tee test.txt"` *does* return output in real time. But `powershell "&\"C:\Program Files\Windows Defender\MpCmdRun.exe\" -Scan -ScanType 3 -File "%CD%" -DisableRemediation | tee -FilePath antivirusLog.txt"` doesn't - it only returns the output after finishing the scan. (What gives? Maybe the `tee` cmdlet somehow caches the output instead of immediately passing it on?) – Mike Rosoft May 11 '23 at 08:33
  • @MikeRosoft My comment was incorrect (deleted), my experiment was flawed. If source process flushes its output stream, Tee does get the data chunk immediately. (I tried flushing early on, but had an unrelated flaw that made it look as if flushing did not help.) Perhaps the process in your example doesn't flush? e.g. in Python: print("foo", flush=True). – alexei May 12 '23 at 09:54
  • You can also wrap this up in a one-line batch file, eg tee.bat: `@powershell -command "$Input | tee '%~f1'"` and add it to your path. Then you can just: `do_the_thing.exe | tee ".\Zhu Li.log"` – maybeWeCouldStealAVan Aug 12 '23 at 01:18
148

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.

Christopher Painter
  • 54,556
  • 6
  • 63
  • 100
NSPKUWCExi2pr8wVoGNk
  • 2,449
  • 2
  • 22
  • 26
  • 123
    This satisfies the answer, but outputs the data after the dir command has completed rather than as the data is produced. – Leigh Riffel Aug 17 '09 at 21:23
  • 12
    it will work, but you will get stuck if the command wait a input from stdin. – Vitim.us Apr 18 '13 at 16:03
  • 5
    I like this simple answer! I found that an `&` instead of a `|` is needed for the output of some commands, like `ping` or `7z.exe` – Wes Larson Feb 20 '16 at 01:14
  • Not working for interactive commands instead of `dir`. Example: `chkdsk /f c: > c:\Temp.txt | c:\Temp.txt` . The system report file is locked by another process. – Sopalajo de Arrierez Jul 08 '16 at 21:13
  • This command does not seem to handle output to stderr. Stderr seems to be printed to the console but is not saved in the file. – Lii Jan 31 '17 at 13:37
  • 5
    @lii re: `handle output to stderr` - Add the `2>&1` redirection so it is like this: `dir 2>&1 > a.txt & type a.txt` and you _should_ have stderr mixed in with stdout. – Jesse Chisholm Jun 01 '17 at 17:28
  • 1
    I agree with @WesLarson, `&` or `&&` is better than a pipe `|`... the pipe may not print the entire redirect for long outputs because it doesn't wait for completion, `&` does wait for completion and is required for delayed output. – u8it Sep 05 '17 at 16:55
  • yeah but i got ugly whitespace, any direction? – Adi Prasetyo Sep 21 '17 at 09:04
  • @JesseChisholm, `dir 2>&1 > a.txt & type a.txt` both redirects the results to a log file and shows them on the screen. But the displaying of result to screen is delayed until the command is done. Is there a way so that the displaying of result to screen happens at the same time it is written to the log file? – Steven Lee Sep 02 '20 at 15:32
  • 1
    @LHC -- Only by using a utility like `tee`. There are various packages to get unlx-like (or linux-like) utilities that run on windows. There is no native Windows way. – Jesse Chisholm Sep 04 '20 at 14:54
  • did not work for me: C:\Data>echo 12 > log.html | type log.html File not found error (Das System kann die angegebene Datei nicht finden.) – Nikolai Ehrhardt Dec 01 '21 at 11:07
  • Just to add another caveat to this solution: If you rely on the errorlevel (aka return code) of the command, the chain to type will overwrite it (e.g. if the first command exits with non-zero, this chain will still return 0 if the file exists) – djm Mar 21 '23 at 11:43
109

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

Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
  • 19
    The link points to a Windows implementation of the Unix command tee, so it does work on Windows. – Brian Rasmussen Apr 28 '09 at 06:50
  • 4
    Yeah, voting up the answer and the comment. I'd actually prefer CygWin since it has everything but some people prefer non-DLL tools that they can pick and choose. – paxdiablo Apr 28 '09 at 07:10
  • 3
    Lots of Unix utilities are also ported by GnuWin32 project, see http://gnuwin32.sourceforge.net/. – VladV Jul 17 '09 at 07:16
  • 2
    UnxUtils was last updated in 2003; GnuWin32 is a bit more up-to-date. – quack quixote Feb 17 '10 at 11:26
  • why use this when there is native support in windows as per the answer below?? – markmnl Nov 29 '11 at 04:39
  • @Feanor: Did you read the comment on that answer? While it works for some cases, it has it's limitation. Both answers are valid and have their uses. – Brian Rasmussen Nov 30 '11 at 03:36
  • 1
    When down voting please leave a comment. Thanks. – Brian Rasmussen Feb 02 '13 at 04:22
  • 11
    If you, like me, struggled to find GnuWin32's `tee` package, you'll find it in http://gnuwin32.sourceforge.net/packages/coreutils.htm. – Nigel Touch Feb 18 '14 at 18:10
  • 1
    More details is here: https://stackoverflow.com/questions/796476/displaying-windows-command-prompt-output-and-redirecting-it-to-a-file/62771772#62771772 – Andry Jul 07 '20 at 09:09
62

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.

Davor Josipovic
  • 5,296
  • 1
  • 39
  • 57
  • 4
    Why the down vote? 95% of replies here have one thing in common: the output is redirected only after the initial command has finished: read the comments. UNIX utility `tee` outputs real time. `wtee` has the same functionality. If you don’t mind the bugs, it will do just fine. – Davor Josipovic Sep 27 '12 at 16:49
  • 1
    That's the only solution working for me, not having Powershell > 4.0. Thumbs up! – Alex Feb 20 '17 at 11:25
  • This should be the accepted answer. `wtee` works on `Win 2003 Srv` at least, starts much faster than `powersell` and can be easily integrated into the building process. – Aleksey F. Oct 09 '21 at 13:46
54

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

Brian Webster
  • 30,033
  • 48
  • 152
  • 225
Andy Welch
  • 557
  • 4
  • 2
  • 22
    You should use `&` instead of `&&` if you want to ensure the `type` command is executed even if `dir` command failed. This is useful when there was some form of error in your command and you still want to see the log file on the console. See [Microsoft's article on this](http://support.microsoft.com/kb/279253). However, this has the issue of `%errorlevel%` being set to the error level of `type` (which would be 0). – ADTC Apr 02 '14 at 04:29
27

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.

Zombo
  • 1
  • 62
  • 391
  • 407
Daniel Rikowski
  • 71,375
  • 57
  • 251
  • 329
27

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.

T.S.
  • 18,195
  • 11
  • 58
  • 78
Richard
  • 1,169
  • 6
  • 8
  • 5
    Hmm, download tee/cygwin for nothing or buy MSVS with my hard-earned cash for a piddly little program like that? That's a tough one :-) – paxdiablo Apr 28 '09 at 07:08
  • 21
    You don't need visual studio to compile that, the commandline tools are actually free. just google ".net sdk download" for the link (the direct link seems to change around but google always seems to work). – Kris Apr 28 '09 at 07:17
  • 13
    Visual Studio Express is free as well, but I would still just use tee for this. – Brian Rasmussen Apr 28 '09 at 07:39
  • Home-made tee implementation? And have to learn C#? Use tee.. really. – Jay Sep 08 '09 at 17:02
  • 7
    cygwin is a pain to install. Upvote to you because this is what I was looking for. – Samaursa Jul 24 '11 at 16:06
  • 1
    I don't think this outputs to the console and the files at the same time does it? – mjaggard Nov 07 '11 at 08:50
  • mjaggard: god point. It could easily be modified to do it though by adding an additional output that WAS the console.out stream. – Brent Rittenhouse Oct 18 '18 at 16:31
  • @paxdiablo Just make a Compilar.bat with this line: C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe %1 and then save his code to CopyToFiles.cs and drag it onto the bat file to create the executable. – FocusedWolf Mar 14 '22 at 22:51
  • You can install cygwin with one line like so: `(setlocal enableDelayedExpansion&set packs=C:\prg\sysdata\cygpackages&mkdir !packs!&cd !packs!&echo !packs!&curl -O "https://cygwin.org/setup-x86_64.exe"&!packs!\setup-x86_64.exe --no-admin -q -n -N -d -R c:\prg\cygwin64 -l !packs!\cygwin64localpacks -s https://cygwin.mirror.constant.com -P wget)`. You can call a program like `c:\prg\cygwin64\bin\tee.exe` or You can add cygwin to the local user's path with: `rundll32 sysdm.cpl,EditEnvironmentVariables`. Add this path: `c:\prg\cygwin64\bin` – David Gleba Apr 25 '22 at 16:56
22

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

MTS
  • 1,845
  • 2
  • 17
  • 18
  • 3
    That's only useful if you want to display the contents AFTER your process has run. And that isn't a hard problem to solve. – Christopher Painter Mar 25 '11 at 19:01
  • 1
    Yeah, I guess this addresses a slightly different problem from what the original poster was asking. – MTS Apr 27 '11 at 22:43
  • 2
    +1 This is how I've always done it. I believe this is the correct answer to the original question and should be marked as so. The trick, as @MTS hints at, is that you actually write to two files: one that gets created per each command/line (hence a single ">" that overwrites each time), and then you type that line to the screen (type _), and finally, you type it again and redirect its output, all the long APPENDING, to your log file with ">>". This is how I've done it for years, though I love the simple "_" temp file. I've always done "tmp.txt" or soemthing. Yeah, delete it afterwards. – eduncan911 Jul 19 '13 at 08:07
  • This is a good approach but I had problems with some errors not getting captured. Putting the `type` commands on separate lines (in a subroutine) fixed that though. – Nate Cook Jun 17 '14 at 23:43
  • Just what I needed for my application. – Alan Oct 07 '14 at 17:26
19

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 its switches and arguments, like so:

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

Notice though, that in this case you have to escape the special cmd-shell characters ">&|" with a "^" each so they only get interpreted by powershell.

e.d.n.a
  • 191
  • 1
  • 6
アリスター
  • 332
  • 2
  • 7
  • 1
    I tried this when building pyqt5.7 on windows 10, it's quite sluggish, console output is not realtime, maybe it's buffered? the log file looks correct though – Shuman Aug 01 '16 at 17:38
  • 3
    All of that is completely wrong. It doesn't work at all for me. The last command gives `'tee' is not recognized as an internal or external command` for obvious reasons. With `2>&1` inside cmd line any output to stderr causes errors from powershell. – Pavel P Mar 12 '17 at 06:24
  • Could be a reference to the PowerShell Tee-Object cmdlet - https://technet.microsoft.com/en-us/library/ee177014.aspx – Bernd Aug 29 '17 at 06:52
  • see https://stackoverflow.com/questions/52970939/right-usage-of-21-tee-or-tee-with-powershell so it's not all red – Pete Kirkham Aug 25 '20 at 10:48
  • @PavelP I guess, your issue was with the last example!? The command was missing the necessary escaping of special characters exposed to cmd. It has now been edited and should work that way! – e.d.n.a Jul 21 '21 at 09:47
18

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.

Mark
  • 181
  • 1
  • 2
10

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

 dir > a.txt | tail -f a.txt
jkdba
  • 2,378
  • 3
  • 23
  • 33
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.

Steve Crane
  • 4,340
  • 5
  • 40
  • 63
  • That tee.bat thing looks nice. Hope OP checks this out. – Jay Sep 08 '09 at 17:06
  • 11
    Note that using TEE.BAT will output after the command has completed, just like the "dir > a.txt | type a.txt" example posted nearby. – adzm Aug 05 '10 at 13:19
8

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

This will help to redirect both STDOUT and STDERR

rashok
  • 12,790
  • 16
  • 88
  • 100
  • This doesn't work. I tried using this to launch the JBoss run.bat and it chokes during startup and the server freezes. There are problems with this method... – djangofan Sep 21 '12 at 00:05
  • @raja ashok, doesn't work for me. I have tried **python.exe 1>file.txt 2>&1 | type file.txt** – neo Dec 15 '16 at 09:56
6

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");
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Any way this could capture the stderr output? I have an annoying exe that outputs everything on the standard error stream (i.e. in order to output to a file normally you would do `file.exe 2>output.txt` – Mark Deven Feb 26 '20 at 04:44
  • I figured it out. You can do it using `file.exe 2>&1|tee.bat` as found here: https://superuser.com/questions/452763/how-to-pipeline-stderr-in-cmd-exe – Mark Deven Feb 26 '20 at 14:07
6

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.

Koder101
  • 844
  • 15
  • 28
  • That feels like a hack. It still can't stream massive output from third party applications that you invoke in your batch file. I'm still impressed this is even possible. – Martin Braun Aug 06 '23 at 21:37
5

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
LarsTech
  • 80,625
  • 14
  • 153
  • 225
Richard K
  • 51
  • 1
  • 1
  • Almost, but it does not display simultaneously - if you have a long running task, you will get no results for long time. – JustAMartin Nov 17 '17 at 15:58
4

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
Andreas
  • 5,393
  • 9
  • 44
  • 53
Dennis
  • 104
  • 3
4

This is not another answer, but more an overview and clarification to the already existed answers like Displaying Windows command prompt output and redirecting it to a file and others

I've found for myself that there is a set of issues what makes a set of tee implementations are not reliable in the Windows (Windows 7 in mine case).

I need to use specifically a tee implementation because have already uses a batch script with self redirection:

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

The script and calls to some utilities inside the script can break the output if used together with a tee utility.


  1. The gnuwin32 implementation:

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

Pros:

  • Correctly handles standard output together with a console progress bar, where the \r character is heavily used.

Cons:

  • Makes console progress bars to draw only in a log file, but it has not duplicated or visible in the console window.
  • Throws multiple error messages Cwrite error: No such file or directory because seems the cmd interpreter closes the pipe/stdout too early and can not self close after that (spamming until termination).
  • Does not duplicate/print the output from the pause command (Press any key to continue...) in the console window.

  1. The wintee implementation:

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

https://github.com/rbuhl/wintee

Pros:

  • Shows a console progress bar both in the console window and in a log file (multiple prints).
  • Does duplicate/print the output from the pause command (Press any key to continue...) in the console window.

Cons:


  1. The UnxUtils implementation:

http://unxutils.sourceforge.net/

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

Pros

  • Shows a console progress bar both in the console window and in a log file (multiple prints).
  • Correctly handles the \r character.
  • Does duplicate/print the output from the pause command (Press any key to continue...) in the console window.

Cons

Not yet found


  1. The ss64.net implementation:

http://ss64.net/westlake/nt

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

Pros:

  • Shows a console progress bar both in the console window and in a log file (multiple prints).

Cons:

  • Incorrectly handles the \r character, output is mixed and messed
  • For some reason does duplicate/print the output from the pause command (Press any key to continue...) in the console window AFTER a key press.

  1. The ritchielawrence mtee implementation:

https://ritchielawrence.github.io/mtee

https://github.com/ritchielawrence/mtee

Pros

  • Shows a console progress bar both in the console window and in a log file (multiple prints).
  • Correctly handles the \r character.
  • Does duplicate/print the output from the pause command (Press any key to continue...) in the console window.
  • The error code retain feature w/o a need to use workaround with the doskey (/E flag, Windows command interpreter: how to obtain exit code of first piped command )

Cons


So, if you are choosing the tee utility implementation between the above, then a better choice is the UnxUtils or mtee.


If you are searching for a better implementation with more features and less issues, then you can use callf utility:
https://github.com/andry81/contools/tree/HEAD/Utilities/src/callf/help.tpl

You can run instead of:

call test.bat | mtee /E 1.log

This:

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

It is better because it can pipe stdout separately from stderr and you can even pipe between processes with Administrator privileges isolation using named pipes.

Andry
  • 2,273
  • 29
  • 28
  • unixutils package link does not working, update package does not include tee utility. There are another tee implementations http://ss64.net/westlake/nt/ and https://www.robvanderwoude.com/unixports.php – user2956477 Jul 07 '20 at 18:51
  • @user2956477 I've added another link. I think the update package should not have all set of utilities, only those the author wants to update. – Andry Jul 08 '20 at 09:45
4

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
)
Ed Radke
  • 41
  • 1
3

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%

Community
  • 1
  • 1
ClearBlueSky85
  • 463
  • 6
  • 13
2

Just like unix.

dir | tee a.txt

Does work On windows XP, it requires mksnt installed.

It displays on the prompt as well as appends to the file.

Corey
  • 1,217
  • 3
  • 22
  • 39
1

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
Cody Barnes
  • 358
  • 3
  • 8
  • I do the same when trying to capture output from a command (IE put it inside a for) but then I just call my standard subfunction to echo to the screen and write to the log because I use it throughout my script in replacement of using echo. Not sure why that got a downvote from others so I upvoted it. – Ben Personick Mar 19 '18 at 15:13
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

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

Vladimir
  • 170,431
  • 36
  • 387
  • 313
7thSphere
  • 27
  • 1
1

If you're on the CLI, why not use a FOR loop to "DO" whatever you want:

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

Great resource on Windows CMD for loops: https://ss64.com/nt/for_cmd.html The key here is setting the delimeters (delims), that would break up each line of output, to nothing. This way it won't break on the default of white-space. The %a is an arbitrary letter, but it is used in the "do" section to, well... do something with the characters that were parsed at each line. In this case we can use the ampersands (&&) to execute the 2nd echo command to create-or-append (>>) to a file of our choosing. Safer to keep this order of DO commands in case there's an issue writing the file, we'll at least get the echo to the console first. The at sign (@) in front of the first echo suppresses the console from showing the echo-command itself, and instead just displays the result of the command which is to display the characters in %a. Otherwise you'd see:

echo Volume in drive [x] is Windows
Volume in drive [x] is Windows

UPDATE: /F skips blank lines and only fix is to pre-filter the output adding a character to every line (maybe with line-numbers via the command find). Solving this in CLI isn't quick or pretty. Also, I didn't include STDERR, so here's capturing errors as well:

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

Redirecting Error Messages

The carets (^) are there to escape the symbols after them, because the command is a string that's being interpreted, as opposed to say, entering it directly on the command-line.

Had To Ask
  • 69
  • 1
  • 4
1

I just found a way to use the perl as alternative, e.g.:

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

pegasus
  • 11
  • 1
0

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

0

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
djangofan
  • 28,471
  • 61
  • 196
  • 289
  • 7
    No, it's not real time, it waits until `%MYCOMMAND%` is finished and it fails in many cases. It skips empty lines, lines beginning with `;` fails with content like `/`, `ON`, `OFF` or `/?`. But the rest could sometimes work :-) – jeb Sep 20 '12 at 18:09
0

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.

The Coordinator
  • 13,007
  • 11
  • 44
  • 73
0

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.
P M
  • 1
0

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.

DannyK
  • 1,342
  • 16
  • 23
0

Another variation is to split the pipe, and then re-direct the output as you like.

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

Save the above to a .bat file. It splits text output on filestream 1 to filestream 3 also, which you can redirect as needed. In my examples below, I called the above script splitPipe.bat ...

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

    splitPipe.bat 2>nul < somefile.txt
Gerhard
  • 22,678
  • 7
  • 27
  • 43
-1
  1. https://cygwin.com/install
  2. Click the link for "setup-x86_.exe"
  3. Run the installer
  4. On ~2nd page, choose a "mirror" to download from (I looked for a .edu domain)
  5. I said ok to the standard options
  6. Cygwin quickly finished install
  7. Open cmd
  8. Type c:\cygwin64\bin\script.exe and enter
  9. Type cmd and enter
  10. Run your program
  11. Type exit and enter (exits Cygwin's cmd.exe)
  12. Type exit and enter (exits Cygwin's script.exe)
  13. See the screen output of your program in text file called "typescript"
Joseph Hansen
  • 12,665
  • 8
  • 50
  • 68