I wrote a script that takes a bunch of options (-d, -v, -l, as well as --version, --leader, etc…) and then the rest of the text ($*) can be anything. The script processes the text and spits it out reformatted. It’s quite long, so here’s a condensed version:
## –––––––––––––––––––––––––[ myScript.sh ]–––––––––––––––––––––––––– ##
# (1) Set up default values
declare -- v='1.0' FS=$':\n\r\v\f\t' Application='Finder' Files s='s'
declare -i errors=0 element=0 counter=0 n L=2
# (2) Parse user input
until [[ -z "$1" || "$1" == '--' || "${1:0:1}" != '-' ]]; do
[ "$Input" ] && unset Input
if [[ "$1" =~ ^(-[Ww]|--[Ww]idth=)([0-9]+)? ]]; then
Input=$(echo "$1" | gsed -re 's|--?W(idth=)?||I' | grep -Eoe '^(0|[1-9][0-9]*)$')
[ -z "$Input" ] && echo "$2" | grep -Eoe '^(0|[1-9][0-9]*)$' && Input="$2" && shift 1
(( Input >= 0 )) && Width="$Input" || unset Width
elif [[ "$1" =~ ^((-[LlIi]|--(([Ll]ead(er|ing)?)?([Ii]n(dent)?)|[Ll]ead(er|ing)?)=)([0-9]+)?)$ ]]; then
Input=$(echo "$1" | gsed -re 's|--?[a-z]+=?||I' | grep -Eoe '^(0|[1-9][0-9]*)$')
[ -z "$Input" ] && echo "$2" | grep -Eoe '^(0|[1-9][0-9]*)$' && Input="$2" && shift 1
(( Input >= 0 )) && L="$Input" || unset L
...
else printf "$(Bold 'Error:') Unrecognized option: '$(Tbrown "$1")'\n\n" >&2
exit 2
fi
shift 1
done
#(3) Now here, get text
IFS=''
[ -n "${*}" ] && declare Text="${*}" || Text="$(cat)" ## could also use read instead of cat ##
[ -z "$Text" ] && printf "$(Bold 'Error:') No text entered...\n\n" >&2 && exit 2
# (4) Process the text
Text="$(echo "$Text" | gsed -rne '1h;1!H;$g;s|[\x0A-\x0D]+| |g;$p' | expand -t4 )"
echo "$Text" ## (temporary) ##
exit 0 ## (temporary) ##
... ## (process text) ##
... ## (process more) ##
Part 3 works for accepting text as entered after options and when piped, but hangs waiting for input if no text is entered and doesn’t see text passed as process substitution… eg:
Examples:
./myScript.sh -L10 --width=20 'This is a test'
> This is a test
echo 'This is a test' | ./myScript.sh -L10 --width=20
> This is a test
./myScript.sh -L10 --width=20 < <( echo 'This is a test' )
> This is a test
./myScript.sh -L10 --width=20 ##*** Want to stop this ***##
> (No output)... hangs waiting on cat (or read) for a ^D
echo 'This is a test' >( ./myScript.sh )
> This is a test /dev/fd/63
> <B>Error:</B> No text entered...
./myScript.sh -L10 --width=20 <<<'This is a test'
> This is a test
echo "This is a test" | tee >( ./myScript.sh -L10 --width=20 ) >( ./myScript.sh )
> This is a test
> This is a test
> This is a test
How do I get the script to not hang on cat or read, waiting for input? (withoout using timeout or read -t as that just slows things down)?
I think what you want here is to avoid reading from a terminal:
It is not possible to detect the general case where no source of input has been provided specifically to the program; all redirection is done by the shell, and your program cannot tell if its standard input was given specifically to it or inherited from the shell.