#!/bin/sh # # shell_select_example # # Example of using "shell_select" in a co-process # https://antofthy.gitlab.io/software/#shell_select # # In this example we send commands to "bc" which can produce both normal output # and errors, and handle them without lockups or problems. basically showing # how you can read from multiple sources of input simultaniously in shell. # # I could have rolled both stdout and stderr into the same file descriptor, and # this is typically what is done. But then I would loose information about # what was real output, and what was error. # # Basically using "shell_select", a shell script can run multiple commands or # network channels in the background and handle them all gracefully. # # NOTE: Due to buffering, "bc" will always accept input. As such that channel # will always be 'ready' for writing. Same goes for network channels unless # you are sending something like more than 8 Mbytes of data! # # Anthony Thyssen # echo "Starting a 'bc' Co-Process (using named pipes in bounre shell)" echo "Note that 10 is 'bc' stdin, 11 is stdout, and 12 is stderr". mkfifo pipe.in pipe.out pipe.err bc pipe.out 2>pipe.err & exec 10>pipe.in 11>>> scale=4; 1.2121*7.312" echo >&10 "scale=4; 1.2121*7.312" echo "" echo "Wait for response (read) and report what fd's are now readable!" echo "shell_select -r 11,12" ready=`shell_select -r 11,12` echo "$ready" eval "$ready" echo "There is output to read, so lets read it." echo "" while true; do case ",$rd_ready," in *,11,*) read <&11 result echo "OUTPUT => $result" ;; *,12,*) read <&12 error echo "ERROR => $error" ;; *) break ;; esac eval `shell_select -t 0 -r 11,12` # poll check for more output done echo "" echo "Reporting what fd's are now ready! (poll)" echo "shell_select -t 0 -w 10 -r 11,12" ready=`shell_select -t 0 -w 10 -r 11,12` echo "$ready" # input only eval "$ready" echo "Again only input (write to the BC command) will be ready." echo "" echo "Send a invalid 'bc' command!" echo ">>>> this is not valid 'bc' request." echo >&10 "this is not valid 'bc' request." echo "" echo "Wait for response and report what fd's are now readable!" echo "shell_select -r 11,12" ready=`shell_select -r 11,12` echo "$ready" eval "$ready" echo "Note that this time we have errors, but no normal output!" echo "If we had just simply read output - we would have locked up!" echo "This is the real point of using a \"shell_select\" command." echo "" echo "Reading Results (errors) from BC command..." while true; do case ",$rd_ready," in *,11,*) read <&11 result echo "OUTPUT => $result" ;; *,12,*) read <&12 error echo "ERROR => $error" ;; *) break ;; esac eval `shell_select -t 0 -r 11,12` # poll check for more errors done echo "" echo "What fd's are now ready? (poll)" echo "shell_select -t 0 -w 10 -r 11,12" ready=`shell_select -t 0 -w 10 -r 11,12` echo "$ready" # input only eval "$ready" echo "Only write to bc (input to command) is ready. -- All done!" echo "" echo "Close all channels and Wait for process to finish" exec 10>&- 11<&- 12<&- wait echo "Final Exit status = $?"