Re: [dev] Shell style guide

From: Nick <suckless-dev_AT_njw.me.uk>
Date: Thu, 8 Sep 2016 13:44:28 +0100

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 $_AT_), 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
Received on Thu Sep 08 2016 - 14:44:28 CEST

This archive was generated by hypermail 2.3.0 : Thu Sep 08 2016 - 14:48:13 CEST