I have here a working method of parsing input arguments however it seems redundant. I would like to shorten this code so it doesn't appear so repetitive.

tool.sh <file-to-use> 
tool.sh <file-to-use> -o <output-file-name> 

# If arguments are set and equals "-o" then set APP_NAME
if [[ -n $3 ]] && [[ $2 = "-o" ]]; then 

# If argument is set and equals anything besides "-o" throw error and show help menu
elif [[ -n $2 ]] && [[ $2 != "-o" ]]; then
    echo "ERROR: Synatx error."
    bash $0 -h 

# If "-o" is set but they did not give a output name throw error and display help menu
elif [[ -z $3 ]] && [[ $2 = "-o" ]]; then
    echo "ERROR: Did not specify output file name."
    bash $0 -h 

Use the ${variable?error message} syntax to error on empty arguments. Use shift to remove parsed arguments from the positional parameters, so that the next unseen argument is always $1. If there are any arguments left at the end, there were too many.

When a message isn't enough, you can use trap … EXIT to call a function on error. Remember to remove the trap after parsing and at the very start of your handler function.

This version isn't any shorter than yours but it's more generic. You can add parameters or rearrange their order without altering the numbers in the existing logic. The error-handling is in one place instead of two.

show_help() { 
 trap - EXIT # omitting this can lead to an infinite loop
 exec $0 -h

trap show_help EXIT
error_usage="Usage: $0 input-file [-o output-file]"
input=${1?$error_usage} && shift
[[ $1 = -o ]] && output=${2?$error_usage} && shift 2
[[ -n $1 ]] && echo $error_usage && exit 0
trap - EXIT

echo "input=$input output=$output"

Rather than invoking ourselves to display help, I'd just put the help logic in the show_help function.

| improve this answer | |
  • \$\begingroup\$ Interesting thanks for the crash course! (Leveling up) \$\endgroup\$ – goose goose May 21 '19 at 23:13

Although tagged , this could easily be portable POSIX shell if we use [ rather than [[.

Always quote strings containing parameter expansions; even though you might think it unlikely that anyone would invoke the script with $0 containing spaces (for example), if you don't code for it, then someone eventually will!

Error messages should always be directed to &2, and error exits should always be non-zero.

Consider using getopt for better argument handling (or at least loop over the arguments and use shift to consume them). Users don't like having to remember that -o filename has to come after the input file; they are used to commands that accept options in any reasonable order.

| improve this answer | |
  • \$\begingroup\$ yes this would be nice but it gets a bit confusing to me when you decide you dont want to use a flag for a input file. \$\endgroup\$ – goose goose May 22 '19 at 23:12
  • \$\begingroup\$ Not a problem, if you say that any non-option argument is an input file. Do you need a demonstration of how that looks? \$\endgroup\$ – Toby Speight May 23 '19 at 7:29

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.