简体   繁体   中英

Sending standard error to standard out not working

I'm having trouble getting the command to send standard error to standard out. I intend to put it in cron, but for now am just running manually.

/home/backups/backup_scripts/backup.sh 2>&1 >> /var/log/backups/backup.log

I was hoping the log file would contain any messages that were printed to standard out, but the log file only showed standard out, and the console output showed the errors.

What am I doing wrong here?

The order of the redirect matters. You should change it to:

/home/backups/backup_scripts/backup.sh >> /var/log/backups/backup.log 2>&1 

This redirects stdout into /var/log/backups/backup.log and then redirects stderr into stdout (which is going into the file).

You can also use the shorter form of:

/home/backups/backup_scripts/backup.sh &>> /var/log/backups/backup.log

&>>file is semantically equivalent to >>file 2>&1

This happened because of the order of the redirections. The 2>&1 means "redirect standard error to the current location of standard out". They are processed left to right so first standard error is redirected to the current standard out (still the terminal) then standard out is redirected to a file. If you switch the order to read

/home/backups/backup_scripts/backup.sh >> /var/log/backups/backup.log 2>&1

it should do what you want. If your shell is bash it has a shortcut to redirect standard out and standard error at the same time: command &> file redirects them both to a file and command &>> file appends both to a file. This order dependency is also mentioned in the bash manual

Note that the order of redirections is significant. For example, the command

 ls > dirlist 2>&1 

directs both standard output and standard error to the file dirlist, while the command

 ls 2>&1 > dirlist 

directs only the standard output to file dirlist, because the standard error was duplicated from the standard output before the standard output was redirected to dirlist.

I think there is some misunderstanding of how file descriptors and redirection works. The kernel has a big table of all the open files on the system that contains the file offset, status flags, and the name of the file itself. Then each process has a table that maps file descriptor numbers to the entries in this global table.

Before any redirections happen the global table might look something like this

A: TERMINAL

and the process table looks like

0: A
1: A
2: A

since descriptor numbers 0, 1, and 2 are stdin, stdout, and stderr respectively.

Then the 2>&1 redirection is processed. This changes the process table so that 2 contains points to the same global entry as 1. However, they are already the same so nothing happens.

When the >> /var/log/backups/backup.log redirection is processed. First the file is opened and assigned to file descriptor 3 in the process table so the tables look like

A: TERMINAL
B: /var/log/backups/backup.log

and

0: A
1: A
2: A
3: B

then standard out is changed to point to the newly opened file (as if 1>&3 were done) so the process table is now

0: A
1: B
2: A
3: B

Note that 2 (stderr) is still pointing to the terminal.

When the redirections are done in the other order, the table after >> /var/log/backups/backup.log looks the same.

0: A
1: B
2: A
3: B

and then the 2>&1 redirection changes what 2 points to giving

0: A
1: B
2: B
3: B

so now stdout and stderr both go to the file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM