from Hacker News

Defensive BASH programming

by jdkanani on 12/15/15, 8:17 AM with 52 comments

  • by catern on 12/15/15, 10:10 AM

    The only thing in this post that can be accurately called defensive is the use of "local" and "readonly". The rest is all just style preferences, which are rather subjective, and none of which are very appealing to me.

    Three real defensive bash programming tips are:

    - Quote all uses of variables

    - set -o nounset

    - set -o errexit

    And many others can be found in and around http://mywiki.wooledge.org/BashFAQ

  • by reacweb on 12/15/15, 9:31 AM

    Very interesting article and I agree with most of the points. One point I strongly disagree is what is called "Code clarity" where the author replaces conditional expressions (https://www.gnu.org/software/bash/manual/html_node/Bash-Cond...) by function calls.

    I agree that the function call introduces a better name. The problem is that this name is specific to the author of the script. It replaces a reusable tricky knowledge of the language by a simple knowledge of the author usages.

    If we take into account the increased verbosity, increased typing, increased number of lines, there is a clear loss in using these functions.

    For me, adding a comment would be far enough and far less annoying.

  • by c0l0 on 12/15/15, 10:22 AM

    A guy publishing a guide for "defensive bash programming", who, in the process, provides this listing as an example for anything, is not fit for publishing said guide in the first place:

      main() {
          local files=$(ls /tmp | grep pid | grep -v daemon)
      }
  • by Gnouc on 12/15/15, 9:03 AM

    It's said that all the example was missing quoting variables. It made all others defensive things useless.
  • by jakub_g on 12/15/15, 10:01 AM

    Slightly off-topic but maybe some people will find it useful:

    I used to write my various glue-things-together scripts in bash, but this quickly becomes a nightmare as the script grows, due to bash's corner cases, syntax, portability issues etc.

    Recently I wrote my massive glue-things-together script with nodejs (since I already use node for many things) and it's much more maintainable and I couldn't be more happy. Node 0.12 has execSync which was the missing piece for making node the proper shell scripting platform.

    If you are interested, you may want to check shelljs [1] and my snippets for robust `exec()` and `cd()` in node.

    [1] https://github.com/shelljs/shelljs [2] https://gist.github.com/jakub-g/a128174fc135eb773631

  • by voltagex_ on 12/15/15, 9:18 AM

    Does anyone know if these ideas conflict with http://mywiki.wooledge.org/BashFAQ or http://mywiki.wooledge.org/BashGuide? These are the resources that are drummed into you on #bash on Freenode, with the strong suggestion that All Other Resources Are Bad And You Should Feel Bad
  • by makecheck on 12/15/15, 2:56 PM

    At some point, "defense" against a language's faults should translate to "use the right language for the job".

    Any sufficiently-complex shell script can usually be written clearly as a Python or Perl program for instance, without having to worry about how the code might be misinterpreted.

    Yes, I write shell scripts sometimes. I just make sure they're doing something pretty straightforward.

  • by ehartsuyker on 12/15/15, 9:00 AM

    I think the best "defensive" piece of advice you left out that everyone abuses is never pipe `find` results to `xargs.` One should always do `find ... -print0` to a read-while loop because of filenames with whitespace.
  • by emmelaich on 12/15/15, 11:35 AM

    The sloshes are redundant after a pipe symbol. i.e.

        ls $dir \
            | grep something
    
    is the same as

        ls $dir |
            grep something
  • by falsedan on 12/15/15, 9:06 AM

    All these recommendation are excellent (except omitting the necessary obsessive quoting of all variables everywhere (just in case they contain a space).

    I've been enjoying BATS [0] for my bash testing.

    [1] https://github.com/sstephenson/bats

  • by ceruleus on 12/15/15, 12:24 PM

    I have always tried to avoid using functions in my bash scripts. That said, it's always nice to other people's bash programming techniques and style. This one had the biggest impact for me, although I can't imagine it's news to any of you on here: http://redsymbol.net/articles/unofficial-bash-strict-mode/
  • by labianchin on 12/15/15, 4:33 PM

    Remembering best practices for BASH might be hard. I recommend using http://www.shellcheck.net/. I use with vim and syntastic. This article talks more about it: http://jezenthomas.com/shell-script-static-analysis-in-vim/
  • by chmielewski on 12/15/15, 1:54 PM

    Content from so long ago, posted here on HN less than two weeks ago... here are some recent reddit comments about the post: https://www.reddit.com/r/bash/comments/3w354v/defensive_bash...
  • by lisivka on 12/15/15, 9:46 AM

    IMHO, it is much easier to parse arguments using bash_modules args module (disclosure: I am author).
  • by matobago on 12/15/15, 9:18 AM

    I'm not sure if scripting can be consider programming. Excessive scripting means lack of software architecture, no to mention the least efficient way to work with the FS
  • by dang on 12/15/15, 9:24 AM

  • by peteridah on 12/15/15, 10:19 AM

  • by moviuro on 12/15/15, 12:21 PM

    This guide is all but ready for prime time. Make it go down, as it is a pile of bad habits. Sure, there are one or two good ideas, but nothing revolutionnary.
  • by IshKebab on 12/15/15, 12:28 PM

    Step 1: Choose a better language. Almost anything will do.
  • by emmelaich on 12/15/15, 11:36 AM

    I quite like

        set -u
        set -e
    
    with

        trap 'echo $0 internal error at $LINENO' ERR
  • by fergie on 12/15/15, 9:25 AM

    I kind of like that BASH allows you to make unconventional programs.
  • by unixhero on 12/15/15, 9:29 AM

    Yes, I applied some of these in my bash program.
  • by Grexception on 12/15/15, 2:27 PM

    To me, BASH is very offensive