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 $< $@ > chmod a+x $@ 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/