154

I have a batch script that executes a task and sends the output to a text file. Is there a way to have the output show on the console window as well?

For Example:

c:\Windows>dir > windows-dir.txt

Is there a way to have the output of dir display in the console window as well as put it into the text file?

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
JamesEggers
  • 12,885
  • 14
  • 59
  • 86
  • [Here](http://www.robvanderwoude.com/redirection.php) are explained the redirections you can make, and some examples.
    Hope it helps :)
    – emoSTN Sep 21 '12 at 11:10
  • 2
    Possible Duplicate: [Displaying Windows command prompt output and redirecting it to a file](http://stackoverflow.com/q/796476/299327) – Ryan Gates Feb 12 '13 at 05:14
  • Please note, @Vadzim, that a question asked on Feb 2 2009 at 16:38 cannot be deemed to be a duplicate of a question asked almost three months later on Apr 28 2009 at 06:32. – Compo Dec 10 '17 at 12:41

12 Answers12

235

No, you can't with pure redirection.
But with some tricks (like tee.bat) you can.

I try to explain the redirection a bit.

You redirect one of the ten streams with > file or < file
It is unimportant, if the redirection is before or after the command, so these two lines are nearly the same.

dir > file.txt
> file.txt dir

The redirection in this example is only a shortcut for 1>, this means the stream 1 (STDOUT) will be redirected.
So you can redirect any stream with prepending the number like 2> err.txt and it is also allowed to redirect multiple streams in one line.

dir 1> files.txt 2> err.txt 3> nothing.txt

In this example the "standard output" will go into files.txt, all errors will be in err.txt and the stream3 will go into nothing.txt (DIR doesn't use the stream 3).
Stream0 is STDIN
Stream1 is STDOUT
Stream2 is STDERR
Stream3-9 are not used

But what happens if you try to redirect the same stream multiple times?

dir > files.txt > two.txt

"There can be only one", and it is always the last one!
So it is equal to dir > two.txt

Ok, there is one extra possibility, redirecting a stream to another stream.

dir 1>files.txt 2>&1 

2>&1 redirects stream2 to stream1 and 1>files.txt redirects all to files.txt.
The order is important here!

dir ... 1>nul 2>&1
dir ... 2>&1 1>nul

are different. The first one redirects all (STDOUT and STDERR) to NUL,
but the second line redirects the STDOUT to NUL and STDERR to the "empty" STDOUT.

As one conclusion, it is obvious why the examples of Otávio Décio and andynormancx can't work.

command > file >&1
dir > file.txt >&2

Both try to redirect stream1 two times, but "There can be only one", and it's always the last one.
So you get

command 1>&1
dir 1>&2

And in the first sample redirecting of stream1 to stream1 is not allowed (and not very useful).

starball
  • 20,030
  • 7
  • 43
  • 238
jeb
  • 78,592
  • 17
  • 171
  • 225
  • 28
    So it is impossible with native windows shell – Fantastory Mar 07 '14 at 10:24
  • 1
    What about the second mechanism "handle duplication"? I experimented with `3<&2` (note the LT instead of GT), and then `3>errors.txt`. But this ended badly - all subsequent stderr output was captured to `errors.txt` (that is - from other commands too!). – Tomasz Gandor Sep 13 '16 at 23:36
  • You could use `for /f "delims=" %%v in ('dir') do echo %%v>>file.txt` though. – amegyoushi Nov 18 '18 at 03:15
  • 3
    @CharlesMcKelvey (and all upvoters) would you have accepted an answer that only says "No"? Or would you have preferred some explanation? – Rodrigo.A92 Jan 10 '20 at 17:03
37

Just use the Windows version of the UNIX tee command (found from http://unxutils.sourceforge.net) in this way:

mycommand > tee outpu_file.txt

If you also need the STDERR output, then use the following.
The 2>&1 combines the STDERR output into STDOUT (the primary stream).

mycommand 2>&1 | tee output_file.txt
Aliaksandr Belik
  • 12,725
  • 6
  • 64
  • 90
atn
  • 371
  • 3
  • 2
  • 4
    The [PowerShell Tee-Object](https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/tee-object) offers similar functionality. Get-Process | Tee-Object -file c:\scripts\test.txt – Kevin Obee Dec 02 '16 at 12:17
  • 1
    I tried this in both powershell and the regular shell. `1>tee a.txt` will redirect stdout to a file named `tee` instead of calling the `tee` command. Can anyone confirm this answer works for them? – mafu Jan 11 '19 at 14:07
  • @mafu I can confirm this. – Cerno Feb 10 '20 at 13:32
  • @mafu The answer above is slightly incorect. You have to use the pipe "|" instead of the ">" in the top example. Weirdly, the order of the STDOUT and STDERR output was mixed up on the command line in that case. The bottom example works perfectly for me though. – Cerno Feb 10 '20 at 13:49
  • Also, the sourceforge download was broken for me. I found an alternative host here: https://www.wzw.tum.de/public-html/syring/win32/UnxUtilsDist.html (University of Munich) – Cerno Feb 10 '20 at 13:50
  • The format did not work for me. I had to use 'mycommand | tee outpu_file.txt' – SpecialK Mar 07 '23 at 21:02
11

If you don't need the output in real time (i.e. as the program is writing it) you could add

type windows-dir.txt

after that line.

Mark Pim
  • 9,898
  • 7
  • 40
  • 59
  • or on the same line (useful at the prompt): `dir > windows-dir.txt & type windows-dir.txt`. This also applies to blocks: `( echo %date% echo %username% echo %time% pause>CON )>test.txt & type test.txt`. However, if the output is required in real time, you can use e.g. a windows port of the **tee** tool for that… – mousio Apr 06 '11 at 21:36
8

The solution that worked for me was: dir > a.txt | type a.txt.

Community
  • 1
  • 1
NSPKUWCExi2pr8wVoGNk
  • 2,449
  • 2
  • 22
  • 26
  • 2
    This works with command with low output. With large output command it don't works because it shows only the first buffer. He it's asking for a real time output while saving the output to a log file. – NetVicious May 02 '16 at 08:58
  • It would be problematic if you use >> instead of > – Nime Cloud May 11 '16 at 08:21
7

Yes, there is a way to show a single command output on the console (screen) and in a file. Using your example, use...

@ECHO OFF
FOR /F "tokens=*" %%I IN ('DIR') DO ECHO %%I & ECHO %%I>>windows-dir.txt

Detailed explanation:

The FOR command parses the output of a command or text into a variable, which can be referenced multiple times.

For a command, such as DIR /B, enclose in single quotes as shown in example below. Replace the DIR /B text with your desired command.

FOR /F "tokens=*" %%I IN ('DIR /B') DO ECHO %%I & ECHO %%I>>FILE.TXT

For displaying text, enclose text in double quotes as shown in example below.

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO ECHO %%I & ECHO %%I>>FILE.TXT

... And with line wrapping...

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO (
  ECHO %%I & ECHO %%I>>FILE.TXT
)

If you have times when you want the output only on console (screen), and other times sent only to file, and other times sent to both, specify the "DO" clause of the FOR loop using a variable, as shown below with %TOECHOWHERE%.

@ECHO OFF
FOR %%I IN (TRUE FALSE) DO (
  FOR %%J IN (TRUE FALSE) DO (
    SET TOSCREEN=%%I & SET TOFILE=%%J & CALL :Runit)
)
GOTO :Finish

:Runit
  REM Both TOSCREEN and TOFILE get assigned a trailing space in the FOR loops
  REM above when the FOR loops are evaluating the first item in the list,
  REM "TRUE".  So, the first value of TOSCREEN is "TRUE " (with a trailing
  REM space), the second value is "FALSE" (no trailing or leading space).
  REM Adding the ": =" text after "TOSCREEN" tells the command processor to
  REM remove all spaces from the value in the "TOSCREEN" variable.
  IF "%TOSCREEN: =%"=="TRUE" (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=On screen, and in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I & ECHO %%I>>FILE.TXT"
        ) ELSE (
          SET TEXT=On screen, not in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I"
      )
    ) ELSE (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=Not on screen, but in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>>FILE.txt"
        ) ELSE (
          SET TEXT=Not on screen, nor in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>NUL"
      )
  )
  FOR /F "tokens=*" %%I IN ("%TEXT%") DO %TOECHOWHERE:~1,-1%
GOTO :eof

:Finish
  ECHO Finished [this text to console (screen) only].
  PAUSE
Amazinate
  • 3
  • 3
Amazinate
  • 71
  • 1
  • 2
3

My option was this:

Create a subroutine that takes in the message and automates the process of sending it to both console and log file.

setlocal
set logfile=logfile.log

call :screenandlog "%DATE% %TIME% This message goes to the screen and to the log"    

goto :eof

:screenandlog
set message=%~1
echo %message% & echo %message% >> %logfile%
exit /b

If you add a variable to the message, be sure to remove the quotes in it before sending it to the subroutine or it can screw your batch. Of course this only works for echoing.

JPZ
  • 31
  • 2
  • WOW YES! I really like this!! I made three changes though, I hope you like them. **1)** I use `setlocal enabledelayedexpansion` instead of just `setlocal` **2)** I use the delayed expansion for the logfile variable, so `>> !logfile!` instead of `>> %logfile%` within the subroutine. This way, it works when called from within a code block (like within an if statement). **3)** I removed the "set message" line because there's no need for the extra variable. We already have it in `$~1` so I have `echo $~1` for both echo commands. – Nate Sep 27 '19 at 18:40
2

If you want to append instead of replace the output file, you may want to use

dir 1>> files.txt 2>> err.txt

or

dir 1>> files.txt 2>>&1
Jochen
  • 380
  • 1
  • 3
  • 9
2
command > file >&1
Otávio Décio
  • 73,752
  • 17
  • 161
  • 228
2

I made a simple C# console which can handle real-time output to both cmd screen and log

class Tee
{
    static int Main(string[] args)
    {
        try
        {
            string logFilePath = Path.GetFullPath(args[0]);

            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                for (int value; (value = Console.In.Read()) != -1;)
                {
                    var word = Char.ConvertFromUtf32(value);
                    Console.Write(word);
                    writer.Write(word);
                }
            }
        }
        catch (Exception)
        {
            return 1;
        }
        return 0;
    }
}

The batch file usage is the same as how you use Unix tee

foo | tee xxx.log

And here is the repository which includes the Tee.exe in case you don't have tool to compile https://github.com/iamshiao/Tee

Circle Hsiao
  • 1,497
  • 4
  • 22
  • 37
1

I like atn's answer, but it was not as trivial for me to download as wintee, which is also open source and only gives the tee functionality (useful if you just want tee and not the entire set of unix utilities). I learned about this from davor's answer to Displaying Windows command prompt output and redirecting it to a file, where you also find reference to the unix utilities.

Community
  • 1
  • 1
sage
  • 4,863
  • 2
  • 44
  • 47
0

The solution provided by "Tomas R" works perfect for the OP's question and it natively available.

Try: chkdsk c: > output.txt | type output.txt

The output is of this command involves a completion percentage that gets serially output to the file hence it will look a bit messy (i.e. the text will be appended as it progress). This does not happen to the bits that gets output to STDOUT (the screen). It is how it would be if you just do the same command without redirection.

J0N
  • 1
-3

I think you want something along the lines of this:

echo Your Msg> YourTxtFile.txt

Or if you want a new line:

echo Your Msg>> YourTxtFile.txt

These commands are great for logs.

Note: This will sometimes glitch and replace the whole text file on my computer.

Another Note: If the file does not exist, it will create the file.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Gladius125
  • 17
  • 3
  • 1
    no, OP wanted to have the output into a file **and** on screen. Yours just writes to file. (And `>` is *designed* to overwrite the file. Use `>>` to *append*) – Stephan Jan 20 '20 at 14:28
  • [Another answer](https://stackoverflow.com/questions/13620748/msgbox-vs-msgbox-in-vbscript/59669761#59669761) was completely bogus, so the confidence is not high. – Peter Mortensen Oct 12 '22 at 23:05