-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!

Porcupine
  • 1,892
  • 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 '21 at 09:03
  • @fra-san Please see the Edit – Porcupine May 13 '21 at 09:41
  • 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 '21 at 09:42
  • @Kusalananda I am sorry, I am not able to understand your question. Basically like we have Stdout Stderr, I would like to create Stdstatus. Stdout can be stored in array and Stdstatus can be printed for user. Does that clarify what I am trying to achieve? I didn't know that stderr could be used for other messages also. But, for the sake of implementing Stdstatus, is it possible? – Porcupine May 13 '21 at 09:46
  • 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?". – Kamil Maciorowski May 13 '21 at 09: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 '21 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 '21 at 16:25

1 Answers1

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

cas
  • 78,579