1521

In bash, calling foo would display any output from that command on the stdout.

Calling foo > output would redirect any output from that command to the file specified (in this case 'output').

Is there a way to redirect output to a file and have it display on stdout?

Mike
  • 397
  • 2
  • 16
SCdF
  • 57,260
  • 24
  • 77
  • 113
  • 6
    If someone just ended up here looking for capturing error output to file, take a look at - https://unix.stackexchange.com/questions/132511/how-to-capture-error-message-from-executed-command – Murphy Oct 18 '17 at 22:19
  • 9
    A note on terminology: when you execute `foo > output` the data *is* written to stdout and stdout *is* the file named `output`. That is, writing to the file *is* writing to stdout. You are asking if it is possible to write both to stdout and to the terminal. – William Pursell May 03 '19 at 11:06
  • 4
    @WilliamPursell I'm not sure your clarification improves things :-) How about this: OP is asking if it's possible to direct the *called program's* stdout to both a file and the *calling program's* stdout (the latter being the stdout that the called program would inherit if nothing special were done; i.e. the terminal, if the calling program is an interactive bash session). And maybe they also want to direct the called program's *stderr* similarly ("any output from that command" might be reasonably interpreted to mean including stderr). – Don Hatch Dec 25 '19 at 21:20
  • If we have multiple commands that want to pipe outputs, use `( )`. For example `(echo hello; echo world) | tee output.txt` – EsmaeelE Dec 11 '22 at 11:51

11 Answers11

2164

The command you want is named tee:

foo | tee output.file

For example, if you only care about stdout:

ls -a | tee output.file

If you want to include stderr, do:

program [arguments...] 2>&1 | tee outfile

2>&1 redirects channel 2 (stderr/standard error) into channel 1 (stdout/standard output), such that both is written as stdout. It is also directed to the given output file as of the tee command.

Furthermore, if you want to append to the log file, use tee -a as:

program [arguments...] 2>&1 | tee -a outfile
gustafbstrom
  • 1,622
  • 4
  • 25
  • 44
Zoredache
  • 37,543
  • 7
  • 45
  • 61
  • 193
    If OP wants "all output" to be redirected, you'll also need to grab stderr: "ls -lR / 2>&1 | tee output.file" – James Brady Jan 12 '09 at 21:53
  • 49
    @evanmcdonnal The answer is not wrong, it just may not be specific enough, or complete depending on your requirements. There certainly are conditions where you might not want stderr as part of the output being saved to a file. When I answered this 5 years ago I assumed that the OP only wanted stdout, since he mentioned stdout in the subject of the post. – Zoredache Oct 01 '14 at 01:30
  • 3
    Ah sorry, I might have been a little confused. When I tried it I just got no output, perhaps it was all going to stderr. – evanmcdonnal Oct 01 '14 at 16:00
  • 47
    Use `-a` argument on `tee` to append content to `output.file`, instead of overwriting it: `ls -lR / | tee -a output.file` – kazy Sep 01 '15 at 15:18
  • I am running it was `python main.py / | tee output.file` and my script thinks that `/` is an argument to the command and is freaking out. Is there a way to deal with this? – Charlie Parker Sep 11 '16 at 21:07
  • Is it possible to make the answer relatively self contained? For example, could explain what each part of the command does, like what does `/`, etc? – Charlie Parker Sep 11 '16 at 21:19
  • `ls -lR /` is overly confusing. It's clearer if you use just something simple like `ls`. – Neal Gokli Sep 21 '16 at 23:52
  • I'm curious about why my edit, which removed `-lR /`, was rejected as "deviates from the original intent of the post.". Maybe the reviewers didn't actually read the question? Or I misunderstood the OP's intent? – Neal Gokli Sep 29 '16 at 05:18
  • @NealGokli I didn't see your edit, I added the `-lR /` to my example to be certain that there was actually output that would show up on the screen. A simple `ls` **might not actually output anything**, like if a user currently in a empty directory, or a directory with hidden files. It is Linux so I could provide tons of other examples that would be certain to provide output. Perhaps something like `od -t x2 /dev/urandom | tee outputfile.txt`. – Zoredache Sep 29 '16 at 06:50
  • Oh, good point! I hadn't thought of that. But isn't `-lR` unecessary? Perhaps a simple `ls -a`? (since at least one person seems to be confused by the `/`. I hate to admit that I was a bit confused at first, too.) Or perhaps using `foo`, from the original question. I'll try another edit :) – Neal Gokli Nov 09 '16 at 19:39
  • 25
    If you're using `$?` afterwards it will return the status code of `tee`, which is probably not what you want. Instead, you can use `${PIPESTATUS[0]}`. – LaGoutte Mar 03 '17 at 14:23
  • for a tool command there are lot of warning messages and errors in terminal but I am not able to get inside a file using > or tee . it only captures the first line – Chandan Choudhury Jan 31 '19 at 12:26
  • 1
    @ChandanChoudhury you probably need to include stderr. IE `... 2>&1 | tee ...` – Zoredache Jan 31 '19 at 18:03
  • 1
    TIL: a case where you don't want to use `tee`: writing to a file from multiple apps simultaneously. While doing that with plain `>>` results in a correct content of a file; but throwing `tee` into the mix results in text being overwritten. – Hi-Angel May 31 '19 at 10:22
  • Note: in modern versions of bash and zsh, you can use `&>` instead of `2>&1`. https://linux.die.net/man/1/bash – catleeball Jun 12 '20 at 23:12
  • 1
    @Hi-Angel `tee` is equivalent to `>` if you want equivalent to `>>` you need to use `tee -a` – Vala Aug 26 '20 at 12:32
  • What is the reason that when I do: `pg_dump | gzip | tee output.gz | gunzip -c` I get input is not in gzip format? – Ali Asgari Sep 13 '20 at 08:12
  • 2
    aside: I was wondering why the command was called `tee`, and realized that a T shape probably represents the information flow. Imagine the information (the output of your command) coming in from the left; it's both directed "downwards" to an output file, and also allowed to carry straight on to `stdout`... – thorimur Jan 02 '21 at 00:04
  • 1
    @thorimur consider that this is being used in a pipe. I am guessing the name was borrowed from the plumbing term. Google 'tee pipe fitting'. – Zoredache Jan 04 '21 at 20:46
  • Note that in some cases you might want to use `tee -i file` (`--ignore-interrupts`) to get tee to ignore the interrupt signal. That's necessary to get the full output from `ping` for example, as the summary is only printed on SIGINT, and tee would terminate without forwarding the signal by default as it doesn't implement SIGINT. – nimser Oct 19 '22 at 10:30
567
$ program [arguments...] 2>&1 | tee outfile

2>&1 dumps the stderr and stdout streams. tee outfile takes the stream it gets and writes it to the screen and to the file "outfile".

This is probably what most people are looking for. The likely situation is some program or script is working hard for a long time and producing a lot of output. The user wants to check it periodically for progress, but also wants the output written to a file.

The problem (especially when mixing stdout and stderr streams) is that there is reliance on the streams being flushed by the program. If, for example, all the writes to stdout are not flushed, but all the writes to stderr are flushed, then they'll end up out of chronological order in the output file and on the screen.

It's also bad if the program only outputs 1 or 2 lines every few minutes to report progress. In such a case, if the output was not flushed by the program, the user wouldn't even see any output on the screen for hours, because none of it would get pushed through the pipe for hours.

Update: The program unbuffer, part of the expect package, will solve the buffering problem. This will cause stdout and stderr to write to the screen and file immediately and keep them in sync when being combined and redirected to tee. E.g.:

$ unbuffer program [arguments...] 2>&1 | tee outfile
Matthew Alpert
  • 5,993
  • 1
  • 16
  • 13
  • Found a solution: [link](http://stackoverflow.com/questions/1408678/getting-another-programs-output-as-input-on-the-fly/1409028#1409028) – Matthew Alpert Sep 01 '11 at 00:44
  • 8
    Anyone know of an 'unbuffer' for osx? – John Mee May 21 '12 at 23:02
  • 9
    If you can't use unbuffer, GNU coreutils includes a tool called [stdbuff](http://www.gnu.org/software/coreutils/manual/html_node/stdbuf-invocation.html) which can be used to prevent output buffering like so `$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile` – Peter Jul 01 '15 at 18:58
  • This, this is exactly what I've been looking for! I'm using tee with a program I did not write and I have to wait about a minute before stdout is flushed. Unbuffer solves this! It's also worth noting that @Peter's solution with stdbuf did not work, I still experienced long wait times before the output appeared in my file. – Ethan Feb 15 '16 at 16:46
  • 2
    If you're using OS X, it's marginally easier to use unbuffer in most cases, although not if you want to pass signals to the command you're running. My comment was more aimed at users who are on Linux, where coreutils is most likely installed by default. @Ethan, see this answer if you're confused about stdbuf syntax: http://stackoverflow.com/a/25548995/942781 – Peter Feb 16 '16 at 15:34
  • @Peter, I'm running Linux mint. I had only tried stdbuf with the arguments you gave in your answer. That's very good to know that there are complications where signals are concerned, luckily my use case is fairly simple. Thanks for the elaboration! – Ethan Feb 16 '16 at 18:10
  • 14
    Note that `python` has a built in option `-u` that unbuffers output. – fabian789 Apr 18 '16 at 15:31
  • 4
    Absolute lifesaver for training ML models where I want to log without extra code but also see the output over the hours/days it takes to run, thank you! – rococo May 28 '19 at 17:10
  • A tip if you are using conda, make sure to install the expect package with conda, https://anaconda.org/Eumetsat/expect – Iyad Ahmed Sep 10 '22 at 09:53
175

Another way that works for me is,

<command> |& tee  <outputFile>

as shown in gnu bash manual

Example:

ls |& tee files.txt

If ‘|&’ is used, command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.

For more information, refer redirection

tsenapathy
  • 5,646
  • 3
  • 26
  • 26
24

You can primarily use Zoredache solution, but If you don't want to overwrite the output file you should write tee with -a option as follow :

ls -lR / | tee -a output.file
Community
  • 1
  • 1
O.Badr
  • 2,853
  • 2
  • 27
  • 36
19

Something to add ...

The package unbuffer has support issues with some packages under fedora and redhat unix releases.

Setting aside the troubles

Following worked for me

bash myscript.sh 2>&1 | tee output.log

Thank you ScDF & matthew your inputs saved me lot of time..

Community
  • 1
  • 1
nitinr708
  • 1,393
  • 2
  • 19
  • 29
12

In my case I had the Java process with output logs. The simplest solution to display output logs and redirect them into the file(named logfile here) was:

my_java_process_run_script.sh |& tee logfile

Result was Java process running with output logs displaying and putting them into the file with name logfile

Jackkobec
  • 5,889
  • 34
  • 34
  • 4
    Perhaps mention that the `|&` shorthand redirects both stdout and stderr into the pipe (equivalent to `2>&1 | ...`). Probably use `tee -a` to append to an existing file. – tripleee Aug 16 '22 at 06:03
10

Using tail -f output should work.

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
Chuck Phillips
  • 812
  • 1
  • 7
  • 15
7

You can do that for your entire script by using something like that at the beginning of your script :

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

This redirect both stderr and stdout outputs to the file called mylogfile and let everything goes to stdout at the same time.

It is used some stupid tricks :

  • use exec without command to setup redirections,
  • use tee to duplicates outputs,
  • restart the script with the wanted redirections,
  • use a special first parameter (a simple NUL character specified by the $'string' special bash notation) to specify that the script is restarted (no equivalent parameter may be used by your original work),
  • try to preserve the original exit status when restarting the script using the pipefail option.

Ugly but useful for me in certain situations.

Bruno BEAUFILS
  • 1,049
  • 11
  • 11
5

Bonus answer since this use-case brought me here:

In the case where you need to do this as some other user

echo "some output" | sudo -u some_user tee /some/path/some_file

Note that the echo will happen as you and the file write will happen as "some_user" what will NOT work is if you were to run the echo as "some_user" and redirect the output with >> "some_file" because the file redirect will happen as you.

Hint: tee also supports append with the -a flag, if you need to replace a line in a file as another user you could execute sed as the desired user.

jorfus
  • 2,804
  • 27
  • 23
2

< command > |& tee filename # this will create a file "filename" with command status as a content, If a file already exists it will remove existed content and writes the command status.

< command > | tee >> filename # this will append status to the file but it doesn't print the command status on standard_output (screen).

I want to print something by using "echo" on screen and append that echoed data to a file

echo "hi there, Have to print this on screen and append to a file" 
Blue
  • 22,608
  • 7
  • 62
  • 92
kiran sai
  • 29
  • 2
-17

tee is perfect for this, but this will also do the job

ls -lr / > output | cat output
Sumit Singh
  • 15,743
  • 6
  • 59
  • 89
kal
  • 28,545
  • 49
  • 129
  • 149
  • 11
    That's an error if output doesn't already exist and it doesn't do what you want if it does, overall it is nonsensical. Perhaps you meant ";" instead of "|" ? – Robert Gamble Jan 07 '09 at 03:24
  • 8
    Even if you used a `;`, the output would be much delayed during a slow command. – Brad Koch Apr 18 '13 at 01:14