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

Reply via email to