Search code examples
bashfile-descriptorio-redirection

In Bash, how to print to stdout when it’s already redirected?


I am writing a Bash function, say func() { … }, that interactively asks user a few questions and then runs a certain command.

The prize here is the stdout of said command, and I expect users to call my function like this: func >outfile, to capture the command’s output in a file.

My question is, how do I print those interactive questions to stdout without polluting the useful output?

In other words: within a function, if stdout has been potentially redirected by the caller, how do I write to the ‘original’ stdout (the terminal), temporarily ignoring caller’s redirect?

Do I have to resort to using stderr for output that semantically doesn’t belong there?


Solution

  • Answering The Original Question

    Create a backup of your original stdout at the point in time when your function is defined, and you can use it at invocation time.

    exec {myfunc_stdout_fd}>&1
    myfunc() {
      echo "Content sent to stdout as defined at invocation time"
      echo "Content sent to original stdout" >&"$myfunc_stdout_fd";
    }
    

    ...whereafter:

    myfunc_out=$(myfunc)
    

    ...stores Content sent to stdout as defined at invocation time in myfunc_out, and immediately writes Content sent to original stdout to the stdout that was defined when the function definition took place.

    See this running in an online interpreter at https://ideone.com/HwHRJ7


    Advice Re: Best-Practice Usage

    Prompts are conventionally written to stderr on UNIX, so for prompting-related purposes, retaining the original stdout isn't generally called for. Prompting on stderr is what read -p does; what bash itself does (like other shells); etc. This is appropriate, as POSIX defines stderr as the appropriate stream for "diagnostic output", which is a category that includes status about what the program is doing at the moment (whether it's ready for more input, f/e).

    See also: