From 7130a6d2e4850ebe1d9394a5522d77d9bccecdaa Mon Sep 17 00:00:00 2001 From: Carl Edquist Date: Fri, 30 Sep 2022 08:06:49 -0500 Subject: [PATCH] terminal: use stderr for terminal progress output, etc Avoid mixing rclone command output with progress output by sending terminal output to stderr. Discussion: The --progress option produces output designed for the terminal, and the terminal library sent all its output to stdout. This is a problem for any command that produces output for further processing, when combined with --progress, because the main command output and the progress output are then sent together to stdout. This is most obviously a problem for the rclone 'cat' command. Say you want to retrieve a large file but output to a pipe for further processing, rather than write it to a file. But you also want rclone to display its progress output as you wait for the transfer. Because both the 'cat' output and the progress output go to stdout, this leaves the progress output as garbage data within the streamed cat output, and also prevents the progress output from being displayed. Notably, other rclone commands like 'ls', 'lsjson', and even 'm5dsum', produce meaningful progress output with the --progress option, but when mixed with the regular command output, it makes both the progress output and the command output unusable. The simple solution here is to send output intended for the terminal (including progress output) to stderr instead of stdout. This way the rclone command output can be redirected as desired from stdout, and the progress output will still go to the terminal attached to stderr. If for some reason the user wants to capture/redirect the terminal/progress output for some other purpose, stderr can be redirected instead. --- lib/terminal/terminal.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/terminal/terminal.go b/lib/terminal/terminal.go index 4eda1abab..bf85077d4 100644 --- a/lib/terminal/terminal.go +++ b/lib/terminal/terminal.go @@ -73,12 +73,12 @@ var ( // Start the terminal - must be called before use func Start() { once.Do(func() { - f := os.Stdout + f := os.Stderr if !IsTerminal(int(f.Fd())) { - // If stdout not a tty then remove escape codes + // If stderr not a tty then remove escape codes Out = colorable.NewNonColorable(f) } else if runtime.GOOS == "windows" && os.Getenv("TERM") != "" { - // If TERM is set just use stdout + // If TERM is set just use stderr Out = f } else { Out = colorable.NewColorable(f)