First, expecting options after non-option arguments is bad practice.
The standard command line interface is to have options before non-option arguments, and allow an optional -- to mark the end of options so you can accept non-option arguments that happen to start with -:
myscript -c -ofile.out -- -file1-.in -file2-.in
Same as:
myscript -co file.out -- -file1-.in -file2-.in
Where, as an example -o is an option that takes an argument, -c one that doesn't, -- marks the end of options, and -file1-.in, -file2-.in are two non-option arguments, taken as such despite starting with - because they are after the -- end-of-option argument.
You can use the standard getopts shell builtin to process options with that standard convention.
To handle input to be given either via command line or stdin, you'd do:
while getopts...; do
# process options
...
done
# option processing done.
shift "$((OPTIND - 1))"
# now the positional parameters contain non-option arguments
if (( $# )); then
args=("$@")
else
# no non-option arguments, read them one per line from stdin
readarray -t args
fi
The ((...)) is a kshism (also supported by bash), readarray a bashism. In sh, you'd do:
if [ "$#" -eq 0 ]; then
# no non-option arguments, read them from stdin
IFS='
' # split on newline
set -o noglob
set -- $(cat) # read and split+glob with glob disabled
fi
Where the result is stored in the positional parameters ($1, $2... "$@") instead of the $args array in the bash example above. Beware that in that case, empty lines are discarded.