1688
votes

To redirect stdout to a truncated file in Bash, I know to use:

cmd > file.txt

To redirect stdout in Bash, appending to a file, I know to use:

cmd >> file.txt

To redirect both stdout and stderr to a truncated file, I know to use:

cmd &> file.txt

How do I redirect both stdout and stderr appending to a file? cmd &>> file.txt did not work for me.

8
I would like to note that &>outfile is a Bash (and others) specific code and not portable. The way to go portable (similar to the appending answers) always was and still is >outfile 2>&1TheBonsai
… and ordering of that is important.Torsten Bronger

8 Answers

2181
votes
cmd >>file.txt 2>&1

Bash executes the redirects from left to right as follows:

  1. >>file.txt: Open file.txt in append mode and redirect stdout there.
  2. 2>&1: Redirect stderr to "where stdout is currently going". In this case, that is a file opened in append mode. In other words, the &1 reuses the file descriptor which stdout currently uses.
382
votes

There are two ways to do this, depending on your Bash version.

The classic and portable (Bash pre-4) way is:

cmd >> outfile 2>&1

A nonportable way, starting with Bash 4 is

cmd &>> outfile

(analog to &> outfile)

For good coding style, you should

  • decide if portability is a concern (then use classic way)
  • decide if portability even to Bash pre-4 is a concern (then use classic way)
  • no matter which syntax you use, not change it within the same script (confusion!)

If your script already starts with #!/bin/sh (no matter if intended or not), then the Bash 4 solution, and in general any Bash-specific code, is not the way to go.

Also remember that Bash 4 &>> is just shorter syntax — it does not introduce any new functionality or anything like that.

The syntax is (beside other redirection syntax) described here: http://bash-hackers.org/wiki/doku.php/syntax/redirection#appending_redirected_output_and_error_output

96
votes

In Bash you can also explicitly specify your redirects to different files:

cmd >log.out 2>log_error.out

Appending would be:

cmd >>log.out 2>>log_error.out
66
votes

In Bash 4 (as well as ZSH 4.3.11):

cmd &>>outfile

just out of box

61
votes

This should work fine:

your_command 2>&1 | tee -a file.txt

It will store all logs in file.txt as well as dump them on terminal.

27
votes

Try this

You_command 1>output.log  2>&1

Your usage of &>x.file does work in bash4. sorry for that : (

Here comes some additional tips.

0, 1, 2...9 are file descriptors in bash.

0 stands for stdin, 1 stands for stdout, 2 stands for stderror. 3~9 is spare for any other temporary usage.

Any file descriptor can be redirected to other file descriptor or file by using operator > or >>(append).

Usage: <file_descriptor> > <filename | &file_descriptor>

Please reference to http://www.tldp.org/LDP/abs/html/io-redirection.html

13
votes

I am surprised that in almost ten years, no one has posted this approach yet:

If using older versions of bash where &>> isn't available, you also can do:

(cmd 2>&1) >> file.txt

This spawns a subshell, so it's less efficient than the traditional approach of cmd >> file.txt 2>&1, and it consequently won't work for commands that need to modify the current shell (e.g. cd, pushd), but this approach feels more natural and understandable to me:

  1. Redirect stderr to stdout.
  2. Redirect the new stdout by appending to a file.

Also, the parentheses remove any ambiguity of order, especially if you want to pipe stdout and stderr to another command instead.

Edit: To avoid starting a subshell, you instead could use curly braces instead of parentheses to create a group command:

{ cmd 2>&1; } >> file.txt

(Note that a semicolon (or newline) is required to terminate the group command.)

3
votes

Redirections from inner script

You could plan redirections from script himself

#!/bin/bash

exec 1>>logfile.txt
exec 2>&1

/bin/ls -ld /tmp /tnt

Running this will create/append logfile.txt, containing:

/bin/ls: cannot access '/tnt': No such file or directory
drwxrwxrwt 2 root root 4096 Apr  5 11:20 /tmp

Log to many different files

You could create two different logfile, appending to one overall log and re-creating another last log:

#!/bin/bash

if [ -e last.log ] ;then
    mv -f last.log last.old
fi
exec 1> >(tee -a overall.log /dev/tty >last.log)
exec 2>&1

ls -ld /tnt /tmp

Running this script will

  • if last.log already exist, rename them to last.old (overwriting last.old if they exist).
  • create a new last.log.
  • append everything to overall.log
  • output everything to terminal.

Simple AND combined logs

#!/bin/bash

[ -e last.err ] && mv -f last.err lasterr.old
[ -e last.log ] && mv -f last.log lastlog.old

exec 2> >(tee -a overall.err combined.log /dev/tty >last.err)
exec 1> >(tee -a overall.log combined.log /dev/tty >last.log)

ls -ld /tnt /tmp

So you have

  • last.log last run log file
  • last.err last run error file
  • lastlog.old previous run log file
  • lasterr.old previous run error file
  • overall.log appended overall log file
  • overall.err appended overall error file
  • combined.log appended overall error and log combined file.
  • still output to terminal