4 ms·
This is an excellent resource. I'd like to re-iterate the author's recommendation to use shellcheck: https://www.shellcheck.net/ https://www.shellcheck.net/ I
by js2 3y ago
This is an excellent resource. I'd like to re-iterate the author's recommendation to use shellcheck:
https://www.shellcheck.net/ https://www.shellcheck.net/
I also like using shfmt on top of that.
(I run them via pre-commit[1] hooks[2,3].)
FWIW, I find writing POSIX-compliant shell rarely necessary. In my 25 years of writing shell scripts, they've nearly always been for automation on a specific OS where portability is not a concern. Arrays are really nice to have. One place I like to use them is for making long commands easier to read. e.g.
cmd=(
some-command
--some-long-option
--another-long-option
--an-option-with-a-value="$value"
)
"${cmd[@]}"
This avoids having to use backslashes so you can comment in-between lines or at the end of any line.
I also almost always prefer the self-documenting long-option to single-letter switches when writing shell scripts. Those single-letter options are to save you typing on the command-line. There's no reason to use them in a script.
When I do write a script for more than one OS (typically macOS and Linux), I have bash on both systems, so I use "#!/usr/bin/env bash" and take care to use only the features that the older version of bash that macOS ships with supports.
Where I have to be more careful is in utilities like find, sed, etc which can differ quite a bit between BSD and Linux.
1. https://pre-commit.com/ https://pre-commit.com/
2. https://github.com/shellcheck-py/shellcheck-py https://github.com/shellcheck-py/shellcheck-py
3. https://github.com/maxwinterstein/shfmt-py https://github.com/maxwinterstein/shfmt-py
- dreamcompiler 3y agoThe author suggests using shellcheck in addition to his recommendations.
- js2 3y agoYou're right! I totally missed that. I've updated my comment.
- dreamcompiler 3y agoI write lots of scripts that need to work on both Linux and MacOS. Although both are POSIX, filenames in MacOS are case-insensitive and often contain spaces. This stuff plays havoc with bash scripts written by naive Linux programmers. Following TFA's recommendations ensures that your scripts will work on both.* * well, except for the fact that MacOS defaults to zsh now.
- js2 3y agoTo be clear: I agree with every recommendation in this article. I just find that writing POSIX-compliant shell is rarely needed. I've clarified my comment.
- drbaba 3y ago> well, except for the fact that MacOS defaults to zsh now. But Zsh is also POSIX sh compatible, is it not?
- meinheld111 3y agoNo. Afaik it can be thou
- distcs 3y agoZsh is not POSIX compatible. You need to enable many flags to make it POSIX compatible. Zsh: $ A="foo bar baz"; for X in $A; do echo $X; done foo bar baz Dash: $ A="foo bar baz"; for X in $A; do echo $X; done foo bar baz
- Calzifer 3y ago> You need to enable many flags to make it POSIX compatible. or use 'emulate sh' to enable many flags at once. (and I personally would prefer if other shells would behave like Zsh and not word split unquoted variables by default)
- JdeBP 3y agoThis is true for the Bourne Again, Watanabe, and Korn shells too. The default mode is not the POSIX-conformant mode, but is the shell's native mode. This does not, however, make these shells "not POSIX compatible" any more than it makes the Z shell "not POSIX compatible". In all of them, one has to do non-default stuff, from setting particular environment variables through invoking the shell with a particular name to adding extra command-line options, to pick the POSIX-conformant mode.
- JdeBP 3y ago
- doctorpangloss 3y ago> In my 25 years of writing shell scripts, they've nearly always been for automation on a specific OS where portability is not a concern. I've written hundreds of scripts for Busybox for Windows (https://github.com/rmyorston/busybox-w32 https://github.com/rmyorston/busybox-w32), Linux bash and macOS zsh. POSIX compatibility means a lot. WRT the specific concerns of arguments: if you are doing something complicated, use Python. ChatGPT writes it better anyway. In my experience, more complex scripting is reinventing Gradle, Ansible, Terraform, YAML & similar.
- js2 3y agoI write a lot of Python too. I've written whole systems in it. Been using it since 1.5.2 days. And before that Perl. I know my way pretty well around sed and awk too and pretty much the entire Unix environment. These are all just tools. They each have their strengths and weaknesses. There are times when shell is the best tool for the job and when it is, I prefer to use bash. If I have to write POSIX shell because it's a constrained environment, sure, I can do it. It's just been something that's rarely been a requirement.
- coldtea 3y ago>if you are doing something complicated, use Python. ChatGPT writes it better anyway. Amusing that this is even a factor
- lelanthran 3y ago> WRT the specific concerns of arguments: if you are doing something complicated, use Python. Introducing Python syntax for this reason alone is way over-engineering your script. Yeah, if you're doing something that requires better data structures[1] then don't use the shell, but switching to Python just to call existing programs makes things more complicated, not less. [1] Arrays, Trees, Dictionaries, etc
- layer8 3y ago> Arrays are really nice to have. One place I like to use them is for making long commands easier to read. …at the cost of making it harder to grok for other people what that code is doing, and having them wonder if there’s some other important reason it has to be written that way.
- latexr 3y ago> I also almost always prefer the self-documenting long-option to single-letter switches when writing shell scripts. Those single-letter options are to save you typing on the command-line. There's no reason to use them in a script. Same applies to Stack Overflow answers and blog posts. If you’re teaching someone how to do something, always use the long flags so they can better understand it as they read. If you don’t know what the long option is, take the two seconds to check the manual.