Hi Evan, I agree with most of your thoughts, I'll just add my own where they differ.
> Shebang: Use #!/bin/sh and only use POSIX shell features. If you need > bash features use the proper shebang, either #!/path/to/bash or > #!/usr/bin/env bash No suckless project should be using bash. If you need the complexity, use rc or something else more fit for the job. > Quoting: Quote all expansions/substitutions. e.g. always use "$foo" > and never use $foo. There are an extremely small number of acceptable > reasons to break this rule, e.g. $CFLAGS (note that some parts of the > grammar do not require quotes for safe expansion such as assignment > and case $var in, we should discuss what to require in these cases) I think this is something one learns with time. There are several good reasons not to quote substitutions, such as passing multiple arguments to another program (e.g. cmd $@), or a for or case statement. But yes, quoting is essential most of the time. Shell escaping sucks, though, obviously. Another reason to keep bourne shell very simple. > Storing Commands: Do not store commands in strings. This is what > functions are for. Storing complex commands in strings and trying > to execute or eval them is fragile and needlessly complex. I actually never use functions in shell scripts; I consider any script that needs them too complex to use shell. I wouldn't be opposed to storing a command name in a string, though, say to store something along the lines of 'convert' vs 'gm convert'. > Command Substitution: Always use "$()", never use backticks. This > makes for easier nesting and fewer surprises. Remember these should > always be quoted. I prefer backticks, because nesting commands is a terrible idea in shell scripts. Keep intermediate output in other variables, if you need to. But if I see nested commands in a shell script there's a high chance I'll rewrite it, if I'm likely to need to actually use / maintain it. > Checking exit status: Do not run a command and then check against $?. > This is pointless. Instead check the exit status directly with if > cmd; then .... or by using a boolean operator such as cmd && ... Generally yes, but there can be times when it's clearer to have the test in a separate statement, for example if the command is long and complex. > Do not parse ls: ls is a tool to view files in a human readable > format. Most often when someone tries to use the output of ls they > really just wanted a glob anyway. I disagree. GNU ls may be, but it isn't supposed to be that way. Something like `ls -tr | tail -n 1` seems perfectly reasonable to me, for example. Sure you could use find, but for some cases ls is simpler. > Test: Do not use parens or boolean operators inside test expressions. > They are deprecated and useless. Instead of [ "$a" = foo -a "$b" = bar > ] use [ "$a" = foo ] && [ "$b" = bar ] Yep. I actually prefer just using the test command rather than [ / ], as I find it clearer, rather than some pseudo-syntactical sugar. But definitely eschewing boolean operators from test is sensible. > Echo and printf: Do not use echo if your input includes a variable or > backslash. There is no safe way to do so. Use printf and %s instead. Agreed. I'd furthermore say that the first argument of printf should always be single-quoted, to ensure no unexpected substitutions can occur. Nick