1

To add options, I have the following in one of my scripts:

parse_opts() {
    while [ $# -gt 0 ]; do
    case "$1" in
        -h|--help)
        help=1
        shift
        ;;
        -r|--raw)
        raw=1
        shift
        ;;
        -c|--copy)
        copy=1
        shift
        ;;
        -s|--sensitive)
        sensitive=1
        shift
        ;;
        -i|--insensitive)
        insensitive=1
        shift
        ;;
        *)
        shift
        ;;
    esac
    done
}

There is only one problem, I cannot use multiple options at the same time. For example, using -r -s works but using -rs does not. How can I programmatically make it work without adding separate entries? The shell I am using is sh.

Edit: I figured out how to do it. It is based on this stackoverflow answer. I copied and pasted it but replaced it with what I need.


New code:

while getopts hcsi-: OPT; do
    # Support long options: https://stackoverflow.com/a/28466267/519360
    if [ "$OPT" = "-" ]; then
        OPT="${OPTARG%%=*}"
        OPTARG="${OPTARG#$OPT}"
        OPTARG="${OPTARG#=}"
    fi
    case "$OPT" in
        h|help) help; exit 0 ;; # Call the `help´ function and exit.
        c|copy) copy=1 ;;
        s|sensitive) case_sensitivity="sensitive" ;;
        i|insensitive) case_sensitivity="insensitive" ;;
        ??*) printf '%s\n' "Illegal option --$OPT" >&2; exit 2 ;;
        ?) exit 2 ;; # Error reported via `getopts´
    esac
done

shift $((OPTIND-1)) # Remove option arguments from the argument list

Amarakon
  • 333
  • which shell is this, specifically? Because zsh does bring a much more powerful option parser. (I'll be honest, I still think "easy to use" is still different, but at least it's possible to implement this if you follow a fixed recipe) – Marcus Müller Jul 05 '22 at 07:22
  • 2
    Have you heard of getopts? – FelixJN Jul 05 '22 at 08:39
  • 4
    @FelixJN, only the getopts from ksh93 does long options though (and not even the same was as GNU getopt_long() does). util-linux getopt can do it though. – Stéphane Chazelas Jul 05 '22 at 10:06
  • The shell I am using is simply sh (dash). – Amarakon Jul 05 '22 at 20:36
  • @FelixJN I have not heard of getopts, how can I use it? – Amarakon Jul 05 '22 at 20:37
  • https://dashdash.io/1/getopt gives an overview of getopt, as recommended by Stéphane. The getopts command is a more powerful builtin which directly modifies shell variables, but you'd have to switch to bash or ksh93. – Henk Langeveld Jul 05 '22 at 21:08
  • @HenkLangeveld, getopts (with the s) is supported in Dash too, and it's a standard (builtin) utility. But it doesn't do long options in most shells. getopt (without the s) isn't standard, and though you get combined short options as well as long options with the util-linux one (which indeed you linked to), you need to be careful to not get the "tradional" ones which can't deal with whitespace in the arguments (and maybe other things) – ilkkachu Jul 05 '22 at 21:58
  • @ilkkachu The options here are all booleans, so getopts could be used with an additional - option taking an argument. All arguments could be handled as normal with getopts and the - option and its option-argument could be handled by an inner case statement. Just thinking aloud... – Kusalananda Jul 05 '22 at 22:38
  • @Kusalananda, hmm, it looks like that might even work? If it treated - the same as letters, it'd eat -- foo (with the space) as the option and option-argument, but it seems to be smarter than that. – ilkkachu Jul 05 '22 at 22:49
  • I figured out how to do it. It is based on this stackoverflow answer: https://stackoverflow.com/a/28466267. I copied and pasted it but replaced it with what I need. – Amarakon Jul 05 '22 at 23:05
  • if you're not going to indent your case statements properly, at least put an empty line between each case to make it somewhat readable. – cas Jul 06 '22 at 07:23
  • 1
    @Amarakon If you have a solution for your specific use case, then consider posting a proper answer. – Kusalananda Jul 06 '22 at 07:48
  • @Kusalananda like I said, I just copy and pasted from a Stack Overflow answer and changed the options. It's better explained there. – Amarakon Jul 06 '22 at 17:16
  • 1
    You linked my answer on Stack Overflow and used it to refine your answer, but I think you missed that its use of getopts makes it vastly more capable than your own implementation. For example, your code doesn't support combining options, like -rc, nor does your code complain given invalid options, nor does it support arguments to options. Follow that link for a better solution implementing long and short options with optional arguments and proper errors. – Adam Katz Mar 08 '23 at 19:54
  • @AdamKatz I did not add the new code block in my post, that was an edit made by someone else. I will update my post with the new code. Sorry for the confusion. – Amarakon Mar 09 '23 at 18:01

0 Answers0