After working with Bash and Shellcheck for a few months, I noticed I could improve my code quality by making it compliant with the Shell Style Guide by Google [0]. While working on that, I thought some aspects of this Shell style guide can be verified automatically, granted some assumptions/opinions are formed. So I looked around for linting tools and autoformatters for Bash:<p>Shellcheck: <a href="https://github.com/koalaman/shellcheck" rel="nofollow">https://github.com/koalaman/shellcheck</a><p>From Asynchronous Lint Engine (ALE): <a href="https://github.com/dense-analysis/ale/blob/master/supported-tools.md" rel="nofollow">https://github.com/dense-analysis/ale/blob/master/supported-...</a><p>- bashate: <a href="https://github.com/openstack/bashate" rel="nofollow">https://github.com/openstack/bashate</a><p>- cspell: <a href="https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell" rel="nofollow">https://github.com/streetsidesoftware/cspell/tree/main/packa...</a><p>- Bash Language Server: <a href="https://github.com/bash-lsp/bash-language-server" rel="nofollow">https://github.com/bash-lsp/bash-language-server</a><p>- shell -n flag: <a href="https://www.gnu.org/software/bash/manual/bash.html#index-set" rel="nofollow">https://www.gnu.org/software/bash/manual/bash.html#index-set</a><p>- sh(shfmt): <a href="https://github.com/mvdan/sh" rel="nofollow">https://github.com/mvdan/sh</a><p>- shdoc: <a href="https://github.com/reconquest/shdoc" rel="nofollow">https://github.com/reconquest/shdoc</a><p>From this stack post [1]:<p>- checkbashisms: <a href="http://man.he.net/man1/checkbashisms" rel="nofollow">http://man.he.net/man1/checkbashisms</a><p>- shlint: <a href="https://github.com/duggan/shlint" rel="nofollow">https://github.com/duggan/shlint</a> (archived)<p>Prettier: <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" rel="nofollow">https://marketplace.visualstudio.com/items?itemName=esbenp.p...</a><p>Within all these linters and auto-formatters I did not find checks that enforce, for example, the Function Comments of the Shell Style Guide by Google:<p>All function comments should describe the intended API behaviour using:<p><pre><code> Description of the function.
Globals: List of global variables used and modified.
Arguments: Arguments taken.
Outputs: Output to STDOUT or STDERR.
Returns: Returned values other than the default exit status of the last command run.
</code></pre>
Hence, I thought we could make a Bash linting tool that verifies compliance with the Shell Style Guide by Google. To do so, a brief start was made here [2]. It identifies/lists elements in that style guide that may be verified automatically. Since Bash has been around longer than me, I think there may be some people better suited for the development of this enhanced linter. Hence, I thought it might be wise, for impact and usability, to share this idea here.<p>What do you say, HN?<p>[0]: <a href="https://google.github.io/styleguide/shellguide.html" rel="nofollow">https://google.github.io/styleguide/shellguide.html</a><p>[1]: <a href="https://stackoverflow.com/questions/3668665/is-there-a-static-analysis-tool-like-lint-or-perlcritic-for-shell-scripts" rel="nofollow">https://stackoverflow.com/questions/3668665/is-there-a-stati...</a><p>[2]: <a href="https://github.com/TruCol/checkstyle-for-bash" rel="nofollow">https://github.com/TruCol/checkstyle-for-bash</a>
I've always been confused that in ${current_year} people are still directly writing huge + complex shell scripts.<p>Compare/contrast Javascript, another language we're "stuck with": while you <i>can</i> still directly write it, many people don't, instead using transpilers to <i>target</i> Javascript as an "object code" from some other, stricter language (e.g. TypeScript, ClojureScript, arbitrary native languages via Emscripten / WASM compiler targets, etc.) Via these languages/compilers, everybody who wants compile-time strictness can have it. And you can even get <i>runtime</i> strictness that Javascript itself doesn't have, as the checked semantics of these languages will often be "lowered" into the resulting Javascript by generating explicit assertions (usually this is on by default, unless you ask for an optimized build.) But the output is still just "Javascript", that any browser can run.<p>Why hasn't a similar thing happened for POSIX-standard Bourne shell? Why are we seemingly "satisfied" with writing + maintaining 5000-line install.sh scripts in our codebases, with a bunch of extra mental overhead / tooling required to keep the code sane and clean; when we could just be writing in a sane and clean language to begin with?<p>Is it just that nobody's bothered to create such a language/compiler? Do I need to be the one to step up, here?
2 things I'd love to see in a checker would be:<p>Warn me when I'm using -h instead of --help. When writing persisted scripts it's often more descriptive and self documenting to use long form flags[0] when a tool gives you both options.<p>Warn me when I mix using "-p 8000:8000" and "-p=8000:8000". I know it's technically not possible to give a definitive answer here because supporting spaces vs equals comes down to the CLI tool itself but you can pick up when you mix the 2 styles and leave it up to the script author to pick a style and stick with it when possible.<p>I do a lot of shell scripting in my day to day (ops, etc.) and it's always a manual process to give feedback on code reviews when others contribute patches or introduce new scripts.<p>[0]: <a href="https://nickjanetakis.com/blog/when-to-use-long-word-or-short-letter-command-line-flags" rel="nofollow">https://nickjanetakis.com/blog/when-to-use-long-word-or-shor...</a>
Take a look at shfmt and shdoc. One is an auto formatter, the other does autodocs. I wouldn't invent yet another docstring format. It's already been done. Just check compliance with an existing format.
Out of pure curiosity, in what context do you write sufficient amounts of Bash scripts that style checking is a worry that needs your attention? While I also write small one-offs or bootstrap scripts here and there, in most cases it's my experience that developers opt for other languages for anything beyond small snippets.
Google's styleguide has incorrect bash being used, they are using string comparison operators for numeric comparisons (see the various `$? != 0` and $PIPESTATUS).<p><pre><code> [[ -1 -eq 0-1 ]] && echo true || echo false
[[ -1 == 0-1 ]] && echo true || echo false
</code></pre>
<a href="https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html" rel="nofollow">https://www.gnu.org/software/bash/manual/html_node/Bash-Cond...</a>
This is a neat idea, but I'm not sure I see the need for this specific tool. Shellcheck covers essentially all the errors that are mentioned in the Google Style Guide so I'd just be using that instead.<p>And as the Guide itself, it is mostly OK, but there are a few things I really don't like. For example:<p>- Whatever doc format they use is not as nice to use as shdoc. Namely, you don't have to add the spaces to your comment to make it formatted properly<p>- The 'no tabs' thing is pretty bullshit - Bash is literally the perfect language to use tabs and their "Whatever you do, don’t use tabs" comment really kills me<p>- I don't like their recommendation of using `[[`. Only using `[[` for stuff like regex and glob matching makes it much easier to paste code between Bash and POSIX sh.<p>There are also a few things they forgot to mention, like the lastpipe` shopt option when talking about piping while loops. And maybe it would be nice to recommend using local like `local var=`. But I guess this guide is meant more for new people that don't know all the pitfalls and stuff<p>But I think I agree there is some need for a more extensible linter. I've been eyeing the Bash LSP, which is based off the Bash Tree Sitter parser, but that has quite a few bugs with parsing that I've been meaning to send PR's for.<p>I wonder if `shfmt` has gotten better since I used it. A few years ago, it was quite buggy with prepending extra whitespace whenever I formatted the file
If your problem can be solved neatly with some combination of existing shell utilities, and you just need a bit of glue to join them together, bash is great.<p>The huge weakness of bash is the data mangling that is more complicated than a relatively simple per-row transformation.
Splitting, joining, sorting, min/max of data structures like arrays, lists and trees are trivial in python, not so in bash. If it's not trivially seddable, and awk doesn't help either because you have to rearrange tree like structures, you are about to experience a massive pain, because it's out of scope of even expertly used associative arrays and you will find yourself reinventing the wheel hard using pretty basic tools.<p>TLDR; As soon as you need to use something more complex than a for loop, switch to Python.
I think we should really be working to deprecate large bash scripts. If you write enough to care about code quality you might want to just use Python.<p>I'd say look at things like Oil(Is that project ever going to be the next big thing like it claims?).... but writing large scripts in ANY shell doesn't seem like the best plan.<p>What about an Ansible linter? Do those exist? I'm starting to suspect Ansible might be a better choice for a lot of what people do with bash, even if you are running om a desktop.