-1

Summary: Like we have Stdout Stderr, I would like to create Stdstatus. Stdout can be stored in array and Stdstatus can be printed for user. I didn't know that stderr could be used for other messages also. But, for the sake of implementing Stdstatus, is it possible?


I have:

SomeFunction(){
  PrintForArray
  echo "Status"
}

mapfile -t SomeArray < <(SomeFunction)

The output of PrintForArray is to be stored in SomeArray, but I also want to print some Status to the command line. The Status must not be stored in the array!

Any suggestions?


Note:

  • This might be useful: What does "3>&1 1>&2 2>&3" do in a script? - Unix & Linux Stack Exchange, but I am not sure how to use this for function

  • Status is meant to be read by the user.

  • It may or may not be stored in a log file (both suggestions are welcomed).

  • I don't want to send it to standard error as the Status is not Error, I just want the User to be informed what is going on!

7
  • 2
    Is "Status" meant to be read by the user? Written to some log file? In other words, your question's title says "to stdout": do you have any particular reason not to send "Status" to standard error?
    – fra-san
    May 13 at 9:03
  • 2
    If you used an ordinary redirection on the command line, would you expect to redirect the status information too? (This is another way to ask fra-san's question) Note that the standard error stream is for any kind of diagnostic messages, not just errors (a better name would have been "standard other stream").
    – Kusalananda
    May 13 at 9:42
  • 1
    I don't want to send it to standard error as the Status is not Error -- stderr is for anything that is not the actual output. It doesn't have to be error information. Diagnostic information may belong to stderr as well. So it's not about "is Status an error?"; it's about "is Status not output?". May 13 at 9:52
  • 1
    The reason NOT to use stderr (rather than, say, &3 as in my answer) is if you want normal handling of stderr (e.g. display on your tty, or redirect it to a logfile or something). If you're absolutely certain that the function or whatever isn't going to print any warnings or error messages on stderr then stderr is OK to use for this kind of back-channel communication.
    – cas
    May 13 at 10:25
  • 1
    "I just want the User to be informed what is going on!" This is why you send messages to standard error, duh. One of the reasons standard error is not affected by ordinary redirection is that the user should see the messages sent to it even if ordinary output is redirected.
    – Kusalananda
    May 14 at 16:25
2

mapfile reads all of stdin to an array, so you can't use the stdout of the function to display messages like "Status".

Try something like this:

$ cat map.sh 
#!/bin/bash

exec 3>&1

SomeFunction(){
  printf "%s\n" {0..3}
  echo "Status" >&3
}

mapfile -t SomeArray < <(SomeFunction)

declare -p SomeArray

Explanation:

  1. First, the script duplicates its stdout to &3.

  2. When mapfile is executed, it reads stdin from the stdout of a process substitution.

    &3 is unaffected by the process substitution, so is still available in the function, and still refers to the script's original stdout (e.g. your tty or wherever the script's output was redirected to), not the redirection.

  3. SomeFunction prints its status message to &3, not to (the redirected) stdout.

Output:

$ ./map.sh 
Status
declare -a SomeArray=([0]="0" [1]="1" [2]="2" [3]="3")

BTW, If you want to do something fancier with "&3" than just have it printed on stdout, you'll have to have the exec statement redirect it to a file or a named pipe or something.

Try either of the following, for example, and you'll find you can't redirect &3. Too late, it's already gone to the script's original stdout:

mapfile -t SomeArray < <(SomeFunction) > /dev/null

mapfile -t SomeArray < <(SomeFunction) 3> /dev/null
5
  • BTW, see How can I redirect all output of a script to a file and replace passwords? for related info about exec and named pipes and process substitution in bash vs sh/ksh/etc.
    – cas
    May 13 at 10:06
  • I observed that your script works even if exec 3>&1 is present just before mapfile. Could you please say why that works?
    – Porcupine
    May 13 at 10:07
  • 1
    because the exec 3>&1 happens before SomeFunction is executed.
    – cas
    May 13 at 10:09
  • But, exec 3>&1 if defined inside SomeFunction just before echo "Status" >&3, Status is not printed! Is there an explanation for this as well?
    – Porcupine
    May 13 at 10:13
  • 1
    If you exec 3>&1 inside the function, the >&3 goes to the function's stdout (which, at this point in time is attached to the stdin of mapfile - and is therefore gobbled up by mapfile to become an element of the array). That's why it has to be exec-ed outside of the function (and before the function is called).
    – cas
    May 13 at 10:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.