0

I have a backup script which I'm asking now to (offer to) call a git pull script before actually running the syncs (when run interactively). The syncs are done thusly:

rsync aiSP --delete 

The backup contains this redirection:

exec 2> "${const_logfile}" 

The git pull script has these two lines:

printf '%s\n' "Shall we pull all the gits?  " 
read -rep "(You will have to enter your git password for each one.)  (y or N) " -n1 

When rsync runs, all of its progress output shows in the terminal (and doesn't get stuffed into the log file). Any error in rsync is added to the logfile.

When the git pull script is called by the backup script the printf line displays in the terminal, but the read text gets stuffed into the log file (and not displayed). This doesn't happen when that script is called directly.

So I pulled that line of redirect code into a test script that contained only that and the git pull script call, so I'm certain that's the culprit. Finally, I added the redirect code directly into the git pull script and called that directly, and the read text again failed to show in the terminal and was sent to the log file.

I would expect the printf text and the read text to go the same route?

I'm sure there's a simple explanation. Or complex. Enlighten me, please.

EDIT:

Raj was helpful; thanks, Raj!

However, there is more I'd like to understand; so, if anyone knows of an article that talks about what qualifies as these extraordinary messages (as Raj has called them) and why it's useful to send them to stderr, I'd love to read more about this.

Also, someone following along may like to know about the -p aspect of read (from here):

-p prompt Display prompt on standard error, without a trailing newline, before attempting to read any input. The prompt is displayed only if input is coming from a terminal.

5
  • From the description of the read command's -p option in the SHELL BUILTIN COMMANDS section of man bash: "Display prompt on standard error" Jan 14, 2021 at 18:51
  • Yeah, I've read the entire read man page. Now help me understand the difference between what is happening with read and with printf. That's why I'm here. @steeldriver
    – JamesIsIn
    Jan 14, 2021 at 18:52
  • I read also this for example: computerhope.com/unix/bash/read.htm
    – JamesIsIn
    Jan 14, 2021 at 18:52
  • Sorry, did you mistype? You wrote standard output twice. @steeldriver
    – JamesIsIn
    Jan 14, 2021 at 18:59
  • Oops yes I did - sorry Jan 14, 2021 at 19:00

1 Answer 1

1

The key to answer is something that you already written in your question: "When rsync runs, all of its progress output shows in the terminal (and doesn't get stuffed into the log file). Any error in rsync is added to the logfile."

That's because the exec command redirects the standard error (but NOT standard output) of the shell that runs the script to the logfile. Regular rsync output is written to stdout (ie. to the terminal), but error messages are written to stderr (ie. to the log file).

It's a commonly used convention in Linux tools that "normal" output is written to stdout, and any "extraordinary" messages that should be shown to the user even when the output is redirected are written to stderr.

Thus, the read prompt is also written to stderr, as it is intended to be shown to the user. On the other hand, printf is intended to display "regular" output, so it writes to stdout (if you want to write to stderr, you can always use printf ... >&2).

Similarly, if you want read prompt to be written to stdout, you can use read ... 2>&1. But what if stdout is redirected?

The correct solution is to remember the "initial" stderr, before it gets redirected by exec (which we hope is a terminal) in another file descriptor and use that descriptor to display the prompt on the "original" stderr.

Before the exec line that you quoted you should put another one:

exec 3>&2

This duplicates the file descriptor 2 (stderr) to file descriptor 3 before the next exec command redirects it. Then in read command use the following redirection:

read ... 2>&3

This should redirect read prompt to file descriptor 3, ie. the original stderr before redirection.

4
  • Could I add exec 3>&2 to the subscript (pull) or would it need to appear prior to the backups redirection? I mean, in the end I can remove the prompt as unnecessary. I really am just trying to understand the (sometimes confusing) redirection processes and the philosophies behind them.
    – JamesIsIn
    Jan 14, 2021 at 19:57
  • I tested what I suggested and it's a nope.
    – JamesIsIn
    Jan 14, 2021 at 20:03
  • Do you know of an article that talks about what qualifies as these extraordinary messages and why it's useful to send them to stderr? @raj
    – JamesIsIn
    Jan 14, 2021 at 20:06
  • exec 3>&2 should appear just before the line with exec 2> "${const_logfile}". It should work, although I didn't test it. As for "extraordinary messages", it's just a matter of common sense. I don't know of any formal specification. Just think this way: everything that user needs to see, even if stdout is redirected to somewhere else, should be written to stderr. For example error messages, hence the name of that stream.
    – raj
    Jan 14, 2021 at 21:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .