ChatGPT解决这个技术问题 Extra ChatGPT

How to redirect output to a file and stdout

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?

If someone just ended up here looking for capturing error output to file, take a look at - unix.stackexchange.com/questions/132511/…
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.
@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).

g
gustafbstrom

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

If OP wants "all output" to be redirected, you'll also need to grab stderr: "ls -lR / 2>&1 | tee output.file"
@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.
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.
Use -a argument on tee to append content to output.file, instead of overwriting it: ls -lR / | tee -a output.file
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]}.
M
Matthew Alpert
$ 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

Anyone know of an 'unbuffer' for osx?
If you can't use unbuffer, GNU coreutils includes a tool called stdbuff which can be used to prevent output buffering like so $ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
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: stackoverflow.com/a/25548995/942781
Note that python has a built in option -u that unbuffers output.
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!
t
tsenapathy

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


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]}.
This method discards colored console output, any ideas?
Try: unbuffer ls -l --color=auto | tee files.txt
C
Community

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

C
Community

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


A
Arsen Khachaturyan

Using tail -f output should work.


B
Bruno BEAUFILS

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.


j
jorfus

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.


J
Jackkobec

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


B
Blue

< 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" 

S
Sumit Singh

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

ls -lr / > output | cat output

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 "|" ?
Even if you used a ;, the output would be much delayed during a slow command.