2120
Comment: clean up
|
2702
add POSIX version of the non-getopts example
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
[[Anchor(faq35)]] | <<Anchor(faq35)>> |
Line 6: | Line 6: |
# Bash while [[ $1 == -* ]]; do case "$1" in -h|--help|-\?) show_help; exit 0;; -v) verbose=1; shift;; -f) output_file=$2; shift 2;; --) shift; break;; esac done |
# Bash while [[ $1 == -* ]]; do case "$1" in -h|--help|-\?) show_help; exit 0;; -v|--verbose) verbose=1; shift;; -f) if (($# > 1)); then output_file=$2; shift 2 else printf "%s\n" "-f requires an argument" exit 1 fi ;; --) shift; break;; -*) echo "invalid option: $1"; show_help; exit 1;; esac done |
Line 18: | Line 24: |
A POSIX version of that same code: {{{ # POSIX while true; do case "$1" in -h|--help|-\?) show_help; exit 0;; -v|--verbose) verbose=1; shift;; -f) if [ $# -gt 1 ]; then output_file=$2; shift 2 else printf "%s\n" "-f requires an argument" exit 1 fi ;; --) shift; break;; -*) echo "invalid option: $1"; show_help; exit 1;; *) break;; esac done }}} |
|
Line 19: | Line 45: |
Line 23: | Line 49: |
# POSIX x=1 # Avoids an error if we get no options at all. while getopts "abcf:g:h:" opt; do case "$opt" in a) echo "You said a";; b) echo "You said b";; c) echo "You said c";; f) echo "You said f, with argument $OPTARG";; g) echo "You said g, with argument $OPTARG";; h) echo "You said h, with argument $OPTARG";; esac x=$OPTIND done shift $(($x-1)) echo "Left overs: $@" |
# POSIX x=1 # Avoids an error if we get no options at all. while getopts "abcf:g:h:" opt; do case "$opt" in a) echo "You said a";; b) echo "You said b";; c) echo "You said c";; f) echo "You said f, with argument $OPTARG";; g) echo "You said g, with argument $OPTARG";; h) echo "You said h, with argument $OPTARG";; esac x=$OPTIND done shift $(($x-1)) echo "Left overs: $@" |
Line 39: | Line 65: |
If your prefer to check options with `if` statements, then a function like this one may be useful: |
If you prefer to check options with `if` statements, then a function like this one may be useful: |
Line 57: | Line 81: |
Line 60: | Line 83: |
and it will work if script is run as: | |
Line 61: | Line 85: |
and it will work if script is run as: *YES: ./script --quick *YES: ./script -other --quick |
* YES: ./script --quick * YES: ./script -other --quick |
Line 65: | Line 88: |
*NO: ./script -bar foo --quick *NO: ./script -bar -- --quick |
|
Line 68: | Line 89: |
* NO: ./script -bar foo --quick * NO: ./script -bar -- --quick |
How can I handle command-line arguments to my script easily?
Well, that depends a great deal on what you want to do with them. Here's a general template that might help for the simple cases:
# Bash while [[ $1 == -* ]]; do case "$1" in -h|--help|-\?) show_help; exit 0;; -v|--verbose) verbose=1; shift;; -f) if (($# > 1)); then output_file=$2; shift 2 else printf "%s\n" "-f requires an argument" exit 1 fi ;; --) shift; break;; -*) echo "invalid option: $1"; show_help; exit 1;; esac done
Now all of the remaining arguments are the filenames which followed the optional switches. You can process those with for i or "$@".
A POSIX version of that same code:
# POSIX while true; do case "$1" in -h|--help|-\?) show_help; exit 0;; -v|--verbose) verbose=1; shift;; -f) if [ $# -gt 1 ]; then output_file=$2; shift 2 else printf "%s\n" "-f requires an argument" exit 1 fi ;; --) shift; break;; -*) echo "invalid option: $1"; show_help; exit 1;; *) break;; esac done
For more complex/generalized cases, or if you want things like "-xvf" to be handled as three separate flags, you can use getopts. (NEVER use getopt(1)!)
Here is a simplistic getopts example:
# POSIX x=1 # Avoids an error if we get no options at all. while getopts "abcf:g:h:" opt; do case "$opt" in a) echo "You said a";; b) echo "You said b";; c) echo "You said c";; f) echo "You said f, with argument $OPTARG";; g) echo "You said g, with argument $OPTARG";; h) echo "You said h, with argument $OPTARG";; esac x=$OPTIND done shift $(($x-1)) echo "Left overs: $@"
If you prefer to check options with if statements, then a function like this one may be useful:
# Bash HaveOpt() { local needle=$1 shift while [[ $1 == -* ]]; do case "$1" in --) return 1; # by convention, -- is end of options $needle) return 0;; esac shift done return 1 } if HaveOpt --quick "$@"; then echo "Option quick is set"; fi
and it will work if script is run as:
- YES: ./script --quick
- YES: ./script -other --quick
but will stop on first argument with no "-" in front (or on --):
- NO: ./script -bar foo --quick
- NO: ./script -bar -- --quick
Of course, this approach (iterating over the argument list every time you want to check for one) is far less efficient than just iterating once and setting flag variables.