On the other hand, I wonder if the web page keeps track and could offer "best of bash mistakes".
But if you're still using Windows, then yes, I agree.
"ShellCheck is...
* GPLv3: free as in freedom
* available on GitHub (as is this website)
* already packaged for your distro or package manager
* supported as an integrated linter in major editors
* available in CodeClimate, Codacy and CodeFactor to auto-check your GitHub repo
* written in Haskell, if you're into that sort of thing. "
Sometimes you are not in your computer, the script does not have private information (i.e. open source or something you don't care to be public). Sometimes the website is simply more convenient.
*edit: formatting
The thing with bash is, it's great for tying things together and quick bits and pieces, but it's not set up for writing maintainable code. Arrays, functions, even if statements comparisons can all be done in bash (as first-class features), but are just... easier in other languages. And then think about the refactoring, linting, testing tools available in bash vs other languages. And then on top of that, there's the issue of handling non-zero return codes from programs you call; do you `set -e`, and exit on any non-zero return code even if you wanted to continue, or not `set -e`, ignoring any errors as your script just continues.
Personally, when I feel I want to use a function (or array, or other similar, non-trivial thing), in bash, it's time to reach for another language.
Having said that, there are some nice programs written in bash. https://www.passwordstore.org/ being one that comes to mind.
Then you must not be writing any bash at all. Functions are useful for almost anything beyond a one-liner script.
Typical functions used in innumerable non-trivial scripts:
* print_usage()
* die() (see: https://stackoverflow.com/q/7868818/1593077)
:-)
With regards to `print_usage()` and `die()`, yes, I would reach for Python 3 then. The `argparse` module and `throw` are first-class members of the stdlib/language and are better and more standard between programs than if I threw together these myself (and with `throw` you get a stack trace, which is nice).
Python is strongly typed. Maybe you meant "statically"? (As opposed to dynamically.)
https://github.com/GavinRay97/hasura-ci-cd-action/blob/a9731...
This is out of necessity. I'm not the sharpest tool in the shed, so I have to go out of my way to write things such that when I come back to them in months or years, I still understand what they do.
For this same reason, is also why I never use shorthand flags for scripts.
I have no clue what IE: "-s -y -o" might do (or even worse, "-syo", dear god my eyes! Also -- is that one special command, or a series of individual commands?!).
But "--silent --assume-yes --output-file" is pretty easy to grok immediately.
Oh man this is so ugly
Not something I would expect in an "elegant" script. Don't think that it is your fault, just it is very hard to write anything elegant in bash.
Hahaha -- fair point. Readable: maybe. Elegant? No. Bash is far from elegant =P
Sorry if I missed something in the logic, reading on my phone, but from the comment, this feels like something I do frequently...
https://ilya-sher.org/2021/03/19/running-elegant-bash-on-sim...
Parsing command-line arguments is easy, but parsing them correctly is ridiculously hard. `getopts` doesn't handle long flags, so it's out. `getopt` doesn't handle arguments with spaces in them, unless you have a version with non-standard extensions, so it's out. You're left with manual parsing, and it's a royal pain to make sure you handle every expected case (short/long flags, clusters of short flags, trailing arguments to be passed through to a subprocess, short/long options whose value is in the next argument, long options whose value is after an equals sign, and several others I'm probably forgetting about). And this is just to get the arguments into your script, before you actually do anything with it.
I agree that bash has effective idioms, and learning those idioms can make scripts easier to write. I strongly disagree that bash is "as maintainable as anything else", and scripts beyond a few hundred lines should be rewritten before they can continue growing.
Is there a feature I'm not seeing that would generate an argument parser without external dependencies?
...
--foo)
FOO="${2:?ERROR: String value is required for \"-f|--foo\" option. See --help for details.}"
shift 2
;;
--foo=*)
FOO="${1#*=}"
shift 1
;;
... while getopts :i:h-: option
do case $option in
# accept -i $input-file, -i$input-file
i ) input_file=$OPTARG;;
h ) print_help;;
- ) case $OPTARG in
help ) print_help;;
help=* ) echo "Option has unexpected argument: ${OPTARG%%=*}" >&2; exit 1;;
in=* ) input_file=${OPTARG##*=};;
in ) echo "Option missing argument: $OPTARG" >&2; exit 1;;
* ) 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))