Re: [dev] Shell style guide

From: Antenore Gatta <antenore_AT_simbiosi.org>
Date: Tue, 6 Sep 2016 22:09:35 +0200

Hi Evan!

Thanks for this, it's something I can finally be involved (at least I hope).

On 09/06/16 20:35, Evan Gates wrote:

> 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

I agree with Hiro, bourne is not bash and scripts should be written in
bourne
shell, not bash... Better, in clean, simple, old style, POSIX compliant
shell.

So, just #/bin/sh

Whatever there is behind is the OS business to make it works like full
POSIX shell.

I write my personal scripts in bash >4.0 or zsh or ksh93, I write portable,
correct scripts in sh.

From man sh:


> DESCRIPTION
> The sh utility is the standard command interpreter for the
system. The
> current version of sh is close to the IEEE Std 1003.1 (“POSIX.1”)
> specification for the shell. It only supports features designated by
> POSIX, plus a few Berkeley extensions. This man page is not
intended to
> be a tutorial nor a complete specification of the shell.


>
> Extension: Do not give your script a .sh extension. An executable
> script is defining a new command. Do you run ls.elf? Furthermore if
> the script is later rewritten in a different language the extension is
> now wrong. It is acceptable to have a script with a .sh extension in a
> project as long as it is then stripped of the extension and made
> executable during the build (just like a .c file would be). The
> following rule already exists as a builtin inference rule in POSIX
> make to do this:
>
> .sh:
> cp $< $_AT_
> chmod a+x $_AT_

I'm not completely agree about this.
A shell script it's not an executable by itself, it's a plain text file,
like a
.c file.

A script installed under /usr/bin (or whatever), yes, it'd be installed
without
extention, that's why you find often that make rule.

Whan you take a look at a project knowing it's extention simplify
finding out
what that files are meant just looking at the extention.

>
> 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)

In my opinion just always. It doesn't make sense having exceptions.


> 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.
>
> Command Substitution: Always use "$()", never use backticks. This
> makes for easier nesting and fewer surprises. Remember these should
> always be quoted.

s/Storing Command/Substituting Commands/

I'm agree but I wouldn't fix a rule about this... Just prefer $()

Remember to quote whatever is inside the the substitute commands and
that you can
nest them:

$(whatever "$foo" $(othercmd "$bar"))

>
> Variable Names: By convention all cap names are reserved for internal
> shell variables and environment variables. If your variable is not
> exported to the environment for use by a child process it should not
> be all caps. Lower case variables also greatly increase readability.

I would also initialize variables in the beginning of the
script/function, for
readibility.

>
> Errexit: Do not use set -e. It is a legacy feature that is broken by
> design and includes many corner cases and gotchas. Check the result of
> each command that can fail and exit if necessary.
>
> 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 && ...
>
> 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.
>
> 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 ]
>
> 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.

Regarding Hiro' comment, the argument against echo is that it's often a
shell
builtin, therefore it may sometimes behave in a strange way.

This is sometimes true, but printf is not safe as well from that point
of view,
as it's a builtin as well in most shells.

In a pure, POSIX, bourne shell implementation printf its the same as the
C printf
function, so it's preferred for formatted output.

In scripts where you just need to output text, or to easily list files,
echo is
fine.

echo *
echo /path/*/whatever/*sh # that is better and faster than "ls"
echo "I'm right"

>
> These cover the most common mistakes I see.
>
> I would be happy to comb through suckless projects and submit patches
> that at least fix broken/dangerous code and preferably style aspects
> as well.

A flame maybe, what do you think about shellcheck? [1]
If it sucks (IMO it doesn't at all), do we need a suckless version.

[1] http://www.shellcheck.net/
Received on Tue Sep 06 2016 - 22:09:35 CEST

This archive was generated by hypermail 2.3.0 : Tue Sep 06 2016 - 22:12:17 CEST