Looking for Tips on Manual Argument Parsing in Bash

0
11
Asked By CodeCrafter123 On

I'm trying to implement a simple manual argument parser for Bash scripts. While I can use `getopts` for short flags, I'm leaning toward long-style options for memorability. I found a template online that does long-style parsing, but it lacks support for combined short options like `-ab`. I'm considering dropping short-style support unless it's easy to add. The following Bash code is what I came across:

```bash
#!/bin/bash
PARAMS=""
while (( "$#" )); do
case "$1" in
-a|--my-boolean-flag)
MY_FLAG=0
shift
;;
-b|--my-flag-with-argument)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
MY_FLAG_ARG=$2
shift 2
else
echo "Error: Argument for $1 is missing" >&2
exit 1
fi
;;
-*|--*=) # unsupported flags
echo "Error: Unsupported flag $1" >&2
exit 1
;;
*) # preserve positional arguments
PARAMS="$PARAMS $1"
shift
;;
esac
done
# set positional arguments in their proper place
eval set -- "$PARAMS"
```

I have some questions: Can this code be improved? Why is `eval` necessary? I think an array might be better than using a string for `PARAMS`. Additionally, is this setup foolproof? I want to avoid using any non-standard libraries, so I'm looking for a solution that balances simplicity with functionality. Lastly, if filenames start with a dash, should I account for that somehow? I know it's possible to modify `getopts` for long options, but I'm unsure if the added complexity is worth it.

4 Answers

Answered By DevDude42 On

You can use a similar approach for handling filenames that start with a dash. Just consider using flags that stop parsing when you hit a `--` or checking the file existence first. Overall, I find that this way, direct error messaging helps improve user experience.

CodeCrafter123 -

Great advice! I’ll definitely look into how to handle that correctly.

Answered By BashWhiz On

One trick is to split combined options like `-vex` into `-v -ex`. Then you can loop through again. Similar formatting works for options with arguments like `-ex` turning into `-e x`, and `--file=foo` as `--file foo`. Here’s a sample snippet for reference:

```bash
while (( $# > 0 )); do
case $1 in
(-[ef]?*) set -- "${1:0:2}" "${1:2}" "${@:2}" ; continue ;;
# Add more cases as needed
esac
shift
done
```

Answered By TechieTim On

The use of `eval` is due to how the script uses a string for `PARAMS`. Starting with an array `PARAMS=()` and adding to it later would allow you to use `set` without `eval`. Here's a quick fix you could try.

```bash
PARAMS=()
while (( "$#" )); do
PARAMS+=("$1")
shift
done
set -- "${PARAMS[@]}"
```

Answered By ScriptGuru99 On

Check out my custom `parse_args` function! It supports both long and short options, allows combining flags, and places everything in new arrays for simplicity. You can find it on my GitHub: [link] 😉

CodeCrafter123 -

That sounds interesting! I'll have to check it out. Thanks for sharing!

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.