1. 8

  2. 12


    • Things should be colorless. Email the output if it failed? Better be colorless. TERM set up wrong due to a screen -> ssh -> screen loop de loop? Better be colorless. Another command grepping/sedding output? Better be colorless..
    • Never use set -e, check each command’s success/failure individually by using mkpipe/mkfifo. as bash does not descriminate on piped failures (just $? == some return code). Rc and it’s related shells set $status to an array and then you can see which commands of the piped command exited with which statuses. You’ll at least want to set -o pipefail as well if you depend on the early exit behavior of bash.
    • Never source scripts, have them output commands that you eval later (or don’t do it all). The reason for this is that it leads to all the same hell that cascading style sheets do.

    My suggestion: use a real programming language, avoid shell scripts to create programmatic environments. Shells should always be the top imperative layer that controls execution flow, never the framework.

    Sorry if this is a harsh reaction, obviously it’s neat to see all the colors and spinning doo-dads, but I think it’s a bad choice.

    1. 5

      I prefer set -euo pipefail to mkpipe/mkfifo.

      Additionally, if you’re writing a shell script without running shellcheck over it, you are either a much better programmer than I am or you’re asking for trouble.

      For instance, shellcheck finds the following in the script you posted:

      • You’ve used /bin/sh rather than bash, but the [[ ]] syntax is undefined in posix SH
      • You’ve used printf with variable interpolation - might as well just use echo or use printf with %s and multiple arguments
      • You’ve defined GREEN but not used it
      1. 1

        If you need shellcheck for your shell script, then you should probably use a better language.

        Does pipefail let you check the exit status of individual portions of a piped command, or does it just bail out?

      2. 5

        I did find the juxtaposition of the sombre and sensible Rule of Silence section with the craaazy colouring and gratuitous emoji in the script immediately following it more than a bit weird. Though on second reading it’s not as bad as my first impression led me to believe. The emoji look cute, the hourglass in particular, but I think I prefer an easily grep-able Warn/Info/Err in general.

        1. 4

          In my opinion, shell scripts are a great way to get a development environment up and running. They are cross-developer as people use them daily and don’t require external bindings themselves.

          With respect to your points:

          • Colorless can be solved by fallback logic to use empty strings if the terminal doesn’t support colors
          • set -e is practical as developers could easily forget to check error codes. In every other language, we throw when there’s a syntax error or missing function. I think everyone expects the same from sh/bash
            • I think you would prefer to use set -o pipefail to catch pipe failures as well
          • I concur with not sourcing scripts, polluting scripts variables from other variables is a pretty bad idea =/
          1. 2

            The coloring fallback logic only works if you have your TERM and pipes set up correctly. This fails in many, oddly practical scenarios to the point that many tools have “–nocolor” or other options because the fallback logic fails many users.

            set -e and set -o pipefail don’t help the script writer catch and do anything with the failures. In many cases you should be printing what failed, and why it failed. Instead, your script ends early, skipping simple cleanup and forcing the person who ran the script to know that it failed, and inspect it’s source code.

            1. 1

              With respect to coloring, you’re right but that’s more on the user than the script itself =/

              With respect to -e and -o pipefail, the same situation happens in programming languaes where there is no catch. It hits the top level and errors out the program. bash has ways to catch/handle these top level errors via trap. I’ve recently been experimenting with it:


              With respect to cleanup, the same issue will arise no matter the language – if someone SIGINT’s a script, it’s unlikely to cleanup properly. To handle a SIGINT in bash, it can be done via trap (either for SIGINT itself or EXIT):

              trap [-lp] [[arg] sigspec ...] command on https://linux.die.net/man/1/bash

              Reference: I use trap to clean up provisioning scripts on ssh scripts which copy data to the remote host

          2. 1

            Sorry if this is a harsh reaction, obviously it’s neat to see all the colors and spinning doo-dads, but I think it’s a bad choice.

            No problem at all, I appreciate your response! I must confess I was swept off my feet by the spinning doo-dads. :)

          3. 2

            BASHism’s in a #!/bin/sh…sacre bleu! :)

            Now, whilst everyone is bike shedding what they think a sh script should look like, my opinion is that -eu should always be used. The things people complain about are trivially worked around with ... || true explicitly where you want to ignore errors as well as the super helpful ${VAR:-...}-esque and $# variables covering the other cases.

            …back to the article though.

            This article touches on what is so important and overlooked in the industry. Dealing with projects which take three days (even for the experienced) to setup a development environment seems to be the norm; less said about the deploy the better too. This leads to situations of either VMs living on laptops for years or a equally awful “Holy USB stick of Truth” being passed around developer to developer to help bootstrap their dive into the project.

            As such, on one knows how to actually then deploy the darn thing.

            Took us at $ORK[-1] a few years of iterations to solve this completely. We went through all the puppet/chef/fabric/etc awfulness and came always back to the same problem that only the system administrators for reasons of skillset plus problem space knowledge and not authorisation could use those tools. In the end we settled on plain shell scripts as it was the common language everyone understood.

            For us the deploy.sh script actually deployed to what could be a debseed minbase’d VM as the dev environment. The same script would we used to deploy to production and it was used to deploy to a system running an earlier commit. The expectation was that it took less than five minutes (rsync and ssh connection multiplexing goes a long way to getting this fast!) to setup from scratch which meant the deploy would be exercised regularly. More so, on a already setup machine, deploying updated code was expected to take seconds which stopped people editing files in place.

            It worked and most importantly everyone understood it including the ‘new guy’. The ‘new guy’ could take to completion themselves their project changes to live on their first day, which they often did.

            We took this a step further and actually got developers using an ‘extinctVM service’ where you would SSH into it and it would give you a blank VM in under five seconds. Further more, when you disconnected, it destroyed it. The carrot to encourage its use was the ‘timebomb’ extension so a developer could edit a file on the filesystem in the VM and instruct it to hang around for a maximum of ten days; coupled with automatic DNS mapping so developers could demo project branches internally to commercial.

            Anyway, as long as the instructions are preflight/deploy level of ease and it and the script actually works, I could not give a two hoots of a care about the ‘how’…the rest is “patches welcome” :)