[HN Gopher] Argbash - Bash Argument Parsing Code Generator
___________________________________________________________________
Argbash - Bash Argument Parsing Code Generator
Author : quincepie
Score : 84 points
Date : 2023-03-20 12:53 UTC (10 hours ago)
(HTM) web link (argbash.dev)
(TXT) w3m dump (argbash.dev)
| caymanjim wrote:
| What's with: # [ <-- needed because of Argbash
|
| There's also this bit:
|
| _The square brackets in your script have to match (i.e. every
| opening square bracket [ has to be followed at some point by a
| closing square bracket ]).
|
| There is a workaround -- if you need constructs s.a.
| red=$'\e[0;91m', you can put the matching square bracket behind a
| comment, i.e. red=$'\e[0;91m' # match square bracket: ]._
|
| That kind of kludginess is a turn-off.
| iamjackg wrote:
| This is very similar to Bashly (https://bashly.dannyb.co/) but
| with a lot more weird magic going on.
| chrsig wrote:
| I really wish bash could evolve...in particular around control
| flow, variable assignment, string interpolation, and arithmetic.
|
| I love working with bash, but it has some footguns that really
| require an expert hand.
|
| I know bash as-is will always be around for backwards
| compatibility with the god-knows-how-many scripts out there. It'd
| just be nice if there were a widely embraced path forward that
| kept the shell scripting spirit while shedding some of the
| unintuitive behaviors
| oweiler wrote:
| I think there is a place for a transpile to Bash language,
| which just adds some tiny bits to fix Bash's idiosyncrasis
| chubot wrote:
| Evolving bash, removing footguns, and providing a path forward
| is exactly what https://www.oilshell.org is about :)
|
| It's run thousands of lines of unmodified shell AND bash
| scripts for years, and provides an upgrade path to a new
| language.
|
| The new language is described here, and you can try it:
| https://www.oilshell.org/release/latest/doc/oil-language-tou...
|
| I've gotten some great feedback on it, but it's not stable yet.
| You can still influence the direction of the language (join us
| on Zulip)
|
| Latest release gives the status of the project:
| https://www.oilshell.org/blog/2023/03/release-0.14.2.html
|
| As an anecdote, one thing that was extremely difficult was
| fixing all the footguns around set -e / errexit in bash.
|
| In shell and bash, "you're damned if you do set -e and damned
| if yuo don't"
|
| However I believe we have done it:
| https://www.oilshell.org/release/0.14.2/doc/error-handling.h...
|
| We simply provide options to make sure that every exit code is
| checked. That's really all. But shells do NOT do this. In fact
| the standard specifies that shells shouldn't, which has left
| people mystified for decades.
|
| I've gotten good feedback about error handling and the rest of
| the changes. Again, you can try it right now if you want to
| verify that the footguns are indeed fixed.
| urxvtcd wrote:
| > As an anecdote, one thing that was extremely difficult was
| fixing all the footguns around set -e / errexit in bash.
|
| Shameless plug: I've recently written a blog post about how
| set -e suddenly ceases to work when using function calls in
| flow control (what you refer to as "disabled errexit quirk"):
| https://snails.dev/posts/set-e.html
|
| Your comment made me interested in Oil, thanks!
| johnchristopher wrote:
| I gave up on bash (more precisely on bashisms. edit: and
| because of bashims) and moved to dash or whatever is at
| /bin/sh. If it can't be done with ash/dash then I look into
| Python or node or PHP or what fits the situation best.
| skowalak wrote:
| I did the same. I believe the biggest selling point of shell
| over other scripting languages is its availability on so many
| platforms. Unfortunately bashisms have ruined the effort of
| writing a one-size-fits-all script. So I, too, moved to POSIX
| shell syntax for the small problems and another shell
| scripting language for the bigger problems.
| dwheeler wrote:
| Bash is very widely available. If you use bashisms like
| arrays, just use bash as the first line.
| nickjj wrote:
| If anyone is looking for a snippet to handle both positional args
| along with required and optional flags (both with short and long
| form formats) along with basic validation I put together:
| https://nickjanetakis.com/blog/parse-command-line-positional...,
| it includes the source code annotated with comments and a demo
| video.
| feisuzhu wrote:
| I've found that every time my bash scripts become sufficiently
| complex, I end up rewriting them in Python.
| [deleted]
| captnswing wrote:
| this ^
| vaughan wrote:
| TypeScript is now tenable for bash scripts with the fast-
| starting Bun runtime https://bun.sh/.
|
| Before Bun, Node+V8 was just too slow to start.
|
| IMHO all scripts should be written in TypeScript...you get
| typechecking and all the rest of the editing experience. Plus
| things like Wallaby.js for live coding/testing.
|
| My `.bashrc` now just runs a TypeScript script with Bun. Allows
| you to use proper structure instead of brittle spaghetti stuff.
| The number of times I'm debugging silly PATH stuff was too
| much...
| c0wb0yc0d3r wrote:
| Do you have an example?
| JohnFen wrote:
| When I'm working on/writing complex bash scripts, it's because
| the scripts have to run on a variety of different customer
| machines where Python is not consistently available (let alone
| being able to count on a particular version) and, if it's not
| there, cannot be installed.
|
| The main advantage of bash is that it exists on just about
| every unix machine.
| vultour wrote:
| Honestly, I don't think I found a single case where this was
| true. Every time I try to rewrite a moderately complex bash
| script in Python it becomes hundreds or thousands of lines of
| code dealing with calling external binaries, streams and proper
| error handling. Perhaps if you're only dealing with text
| processing it will work, but the moment you start piping
| together external programs via Python it's all pointless.
| epr wrote:
| Glad I'm not the only one. Honestly, whenever bash comes up
| in any context, 10 different people feel compelled to express
| this whole replace all bash scripts with python sentiment and
| I just have no clue what the fuck they're talking about.
|
| I would consider myself an expert or at least near-expert in
| python, but I don't see opportunities to replace my shell
| scripts with python popping up left and right. Do you open
| files manually and set up pipe chains with subprocess.Popen?
| I've done this, and its generally many more LOC compared to
| the shell original, and harder to read.
|
| On the other hand, I'd consider myself maybe 7/10 skill level
| with bash, but most developers are only ever a 2/10 or 3/10
| with bash/shell. I can't help but think that the average
| developer's lack of shell understanding is where all these
| suggestions to convert to python come from. If it's that easy
| or beneficial to convert to python, then it probably should
| have been written in python originally.
| iamjackg wrote:
| 100% agree. There are some libraries like
| https://amoffat.github.io/sh/ that aim to make that easier,
| but they always have some quirks that, funnily enough, are
| often the corner cases you were hitting in your complicated
| Bash script in the first place.
| ff317 wrote:
| Yeah, I figure if a bash script goes over ~10-20 lines, or
| involves really long lines, or quotes within quotes within
| quotes of different kinds, it's time to move on to Python or
| similar.
| jen20 wrote:
| Fair - I find that every time a Python program becomes
| sufficiently complex though (defined as "needs something not in
| the stdlib of Python 3.6"), I end up rewriting them in Go or
| Rust ;-)
| Joker_vD wrote:
| Huh, it uses M4 to build its DSL, how quaint.
|
| I wish there were more projects on the other side of the
| spectrum: take the script's self-reported usage string, a la
| docopt [0], and derive argument-parsing code from _that_. After
| all, we have GPT-4 now.
|
| [0] https://github.com/docopt/docopts
| softskunk wrote:
| as cool as this is, i feel that anything with the complexity of
| more than one or two arguments should really be written in a
| different language, like Python (or AppleScript for macOS users).
| bash just isn't the right tool for the job then.
| meindnoch wrote:
| >or AppleScript for macOS users
|
| You must be joking.
| user3939382 wrote:
| AppleScript: It's easy because you write it like natural
| English! Sort of. We'll it's not really natural English. It
| also doesn't have semantics that make sense for a programming
| language. Good luck!
| xp84 wrote:
| Hey but don't worry, it has great documentation, in the
| form of question posts from 2006 on "MacOSXHints" that may
| or may not have been answered!
|
| Also don't worry, you can write AppleScript in JavaScript
| syntax too! Too bad 100% of the code samples out there to
| help you are in the "other" syntax :D
| user3939382 wrote:
| I never had another interpreter that I had to learn by
| manually fuzzing it. AppleScript makes bash look like F#.
| nadaviv wrote:
| GPT is pretty good at figuring out argument parsing code based on
| example CLI usage. Like this: > Write bash code
| to parse the following arguments: > > $
| ./export.sh --out-file dump.json --db foo.sqlite --include-
| headers --exclude-rev -vvv -p9000 Here's an example
| bash code to parse the arguments: #!/bin/bash
| # Default values for optional arguments
| INCLUDE_HEADERS=false EXCLUDE_REV=false
| VERBOSE_LEVEL=0 PORT=0 # Parse the arguments
| while [[ "$#" -gt 0 ]]; do case $1 in
| --out-file) OUT_FILE="$2"; shift ;; --db) DB="$2";
| shift ;; --include-headers) INCLUDE_HEADERS=true ;;
| --exclude-rev) EXCLUDE_REV=true ;; -v)
| VERBOSE_LEVEL=$((VERBOSE_LEVEL+1)) ;; -p) PORT="$2";
| shift ;; -h|--help) echo "Usage:
| ./export.sh [OPTIONS]" echo ""
| echo "Options:" echo "--out-file Output file
| path (required)" echo "--db Database
| path (required)" echo "--include-headers Include
| column headers in output (default: false)" echo "
| --exclude-rev Exclude revisions in output (default: false)"
| echo "-v Increase verbosity level (default: 0)"
| echo "-p Port number (default: 0)"
| echo "-h, --help Show help" exit 0
| ;; *) echo "Unknown parameter passed: $1"; exit 1 ;;
| esac shift done # Check required
| arguments if [[ -z $OUT_FILE ]]; then echo
| "Error: missing argument --out-file" exit 1
| fi if [[ -z $DB ]]; then echo "Error:
| missing argument --db" exit 1 fi
| # Print parsed arguments echo "OUT_FILE=$OUT_FILE"
| echo "DB=$DB" echo "INCLUDE_HEADERS=$INCLUDE_HEADERS"
| echo "EXCLUDE_REV=$EXCLUDE_REV" echo
| "VERBOSE_LEVEL=$VERBOSE_LEVEL" echo "PORT=$PORT"
| version_five wrote:
| Honestly nobody cares. It's insulting to every reader to post
| this kind of crap.
| nadaviv wrote:
| Why is it insulting to point out that GPT can produce good
| results for this particular use-case?
|
| Being able to define your argument types and generate parsing
| code for them using an example CLI invocation feels very
| natural and expressive to me. I personally found it to be
| useful for my work.
| akira2501 wrote:
| I wish it was crap, then I could pretend I'm participating in
| some form of modern performance art. This is, unfortunately,
| just propaganda.
| nadaviv wrote:
| Wait what? Propaganda? I really don't get why this is
| invoking such strong reactions...
| shaftway wrote:
| I've always assumed that there was some argument parser available
| that just sets things as environment variables, and that my
| google-fu is just too weak to find it.
|
| Why ccouldn't I just go `source argbash _ARG_ --single option o
| --bool print --position positional -- $@` and get _ARG_OPTION,
| _ARG_PRINT, and _ARG_POSITIONAL environment variables set based
| on the commands passed in, without having to dump a hundred lines
| of code in my script?
| akho wrote:
| Yet another point where Fish is a delight.
|
| Going to Python/whatever is not quite the same -- shell scripts
| are not as much written as extracted from shell history, so
| switching to a separate language is a large extra step.
| databasher wrote:
| Handling command-line arguments in Bash is easy. Bash's `getopts`
| handles short and long arguments gnu-style without any problem,
| out of the box, without any need for libraries or complicated
| packages.
|
| This pattern handles lots of styles of options: short and long
| options (-h, --help), `--` for separating options from positional
| args, with GNU-style long options (--output-file=$filename).
| while getopts :o:h-: option do case $option in
| h ) print_help;; o ) output_file=$OPTARG;;
| - ) case $OPTARG in help ) print_help;;
| output-file=* ) output_file=${OPTARG##*=};;
| * ) echo "bad option $OPTARG" >&2; exit 1;;
| esac;; '?' ) echo "unknown option: $OPTARG" >&2;
| exit 1;; : ) echo "option missing argument: $OPTARG"
| >&2; exit 1;; * ) echo "bad state in getopts" >&2;
| exit 1;; esac done shift $((OPTIND-1))
| (( $# > 0 )) && printf 'remaining arg: %s\n' "$@"
| sacnoradhq wrote:
| I don't know where you learned shell scripting, but your
| formatting is very confusing and nonstandard.
|
| - while...; do / if ...; then
|
| - space before ;;
|
| - no space before case match
|
| - use util-linux getopt because getopts doesn't handle long
| args
|
| - DRY with a die() function rather than exits littered all over
| databasher wrote:
| If you refer to my example above, you'll find that Bash's
| native "getopts" handles long options just fine. It accepts
| short option `-`, with an argument. This handles --long-
| options and --long-options=with-arguments.
|
| Feel free to use your own formatting preferences.
| sacnoradhq wrote:
| https://google.github.io/styleguide/shellguide.html
| fsckboy wrote:
| > _I don 't know where you learned shell scripting, but your
| formatting is very confusing_
|
| i don't know where you learned English composition, but I
| can't follow your critique. are you pointing out your
| preferences (which may well match gnu or bsd standards, i
| don't know tell me) or things that actually make a
| difference? Did he break emacs auto-indent? Are you pointing
| out all the flaws or the correct ways, i'm having to eyeball
| diff. Use more of your words. while
| do
|
| doesn't seem substantially worse/confusing compared to
| while;do unless you have some reason?
|
| spacing out ;; does it make a difference? or do you like
| things spaced out?
|
| etc.
| sacnoradhq wrote:
| Flagged for not being a professional response to
| constructive feedback.
| yesenadam wrote:
| I thought it was "professional", helpful, and a great
| comment. I didn't think yours was constructive, just
| unhelpfully treating a different formatting style as
| objectively worse, in an unfriendly way. "Be kind"! It
| was also hard to parse, as the GP pointed out.
|
| edit: You changed your comment after I wrote this. Now it
| mentions that you flagged the GP. That's ridiculous.
| sacnoradhq wrote:
| You have way too much time on your hands and seem
| determined to argue nonconstructively. Have a good one.
| yesenadam wrote:
| > You have way too much time on your hands and seem
| determined to argue nonconstructively. Have a good one.
|
| Please refresh on the guidelines. And reconsider who has
| been "constructive" vs "nonconstructive" in this thread.
| rickydroll wrote:
| I have used are - for many projects and it is wonderful. But as
| others have indicated, be mindful of whether or not Bash is the
| right tool for the task at hand.
| synergy20 wrote:
| what is 'are', interesting name
| philote wrote:
| Heh, I'm guessing it was voice to text for "argbash" but got
| translated to "are dash".
| simonw wrote:
| Languages that I work with infrequently enough to remember how to
| use them - like Bash - are the absolute perfect place to apply
| LLM tech like ChatGPT.
|
| Prompt:
|
| > Write a bash script "foo.sh" that accepts a required filename,
| optional flags for "-r/--reverse" and "-s/--skip" and an optional
| "-o/--output=other-file" parameter. It should have "-h/--help"
| text too explaining this.
|
| Then copy and paste out the result and write the rest of the
| script (or use further prompts to get ChatGPT to write it for
| you).
|
| Could it be done better if I spent more time on it or was a Bash
| expert? Absolutely, but for most of the times when I need to do
| something like this I really don't care too much about the
| finished quality.
| ndsipa_pomu wrote:
| I'm a fan of BashBoilerPlate (Bash3BoilerPlate) -
| https://github.com/xwmx/bash-boilerplate
|
| It uses a similar style of deriving the arguments from the usage
| declaration, but it also includes some useful logging functions
| and is all in one script. There's some more info available on
| their style choices here: https://bash3boilerplate.sh/
| tveyben wrote:
| I have great pleasure when using docopt in Python.
|
| I see docopts is 'the same' implementation but for shell, have
| never tried it though.
|
| ==== docopt helps you:
|
| - define the interface for your command-line app, and -
| automatically generate a parser for it. ====
|
| http://docopt.org/
|
| https://github.com/docopt/docopts
| sacnoradhq wrote:
| Cute and lots of effort went into this, but code generation is,
| unfortunately, unmaintainable and inflexible. This seems targeted
| at users who want to avoid mastery of their tools, which is fine
| for some.
|
| util-linux getopt exists.
| [deleted]
___________________________________________________________________
(page generated 2023-03-20 23:01 UTC)