[linux] 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?

This question is related to linux bash file-io io stdout

The answer is


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.


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


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.


Another handy alternative is to use screen command to run the main program and direct the stderr and stdout to a file, then use tail -f to view the file as it is being written to.

You could also open another session if you don't want to use screen.


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

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

ls -lr / > output | cat output

$ 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

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

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.


Using tail -f output should work.


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.


Another handy alternative is to use screen command to run the main program and direct the stderr and stdout to a file, then use tail -f to view the file as it is being written to.

You could also open another session if you don't want to use screen.


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


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

Using tail -f output should work.


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

ls -lr / > output | cat output

Using tail -f output should work.


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

ls -lr / > output | cat output

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

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to file-io

Python, Pandas : write content of DataFrame into text File Saving response from Requests to file How to while loop until the end of a file in Python without checking for empty line? Getting "java.nio.file.AccessDeniedException" when trying to write to a folder How do I add a resources folder to my Java project in Eclipse Read and write a String from text file Python Pandas: How to read only first n rows of CSV files in? Open files in 'rt' and 'wt' modes How to write to a file without overwriting current contents? Write objects into file with Node.js

Examples related to io

Reading file using relative path in python project How to write to a CSV line by line? Getting "java.nio.file.AccessDeniedException" when trying to write to a folder Exception: Unexpected end of ZLIB input stream How to get File Created Date and Modified Date Printing Mongo query output to a file while in the mongo shell Load data from txt with pandas Writing File to Temp Folder How to get resources directory path programmatically ValueError : I/O operation on closed file

Examples related to stdout

Redirect echo output in shell script to logfile Reusing output from last command in Bash Running powershell script within python script, how to make python print the powershell output while it is running Scanf/Printf double variable C Python: How to get stdout after running os.system? How to open every file in a folder Redirect all output to file using Bash on Linux? What does it mean to write to stdout in C? logger configuration to log to file and print to stdout How to get Rails.logger printing to the console/stdout when running rspec?