1. 29

  2. 14

    I usually expose -x via a flags like --trace/--debug. You can also invoke it manually with bash -x ze_script. I wouldn’t turn it on by default.

    1. 2

      -x is really useful when writing Dockerfiles, so you can do:

      RUN set -x \
          && my-command \
          && my-2nd-command

      This way you get clear picture of what’s happening while doing image builds.

      EDIT: formatting

      1. 2

        I definitely agree. I think it’s tempting to think trace output like this means you don’t have to work on log messages and error messages for human beings, and the result is a giant wall of pretty inscrutable output to sift through to sort out what went wrong.

      2. 5

        Suggested next step: shellharden or shellcheck. (TODO: actually start using them myself… :/). See also the amazing “How to do things safely in bash”!

        1. 4

          I’ve heard that bash scripts should always be written with -e, and I usually do use that flag, but if I remember correctly it halts test-suite execution prematurely (like if you’re testing a failure case) if you’re doing TDD in bash with shunit2.

          1. 7

            You can turn it off again with set +e. But usually you’d “handle” the exit status with an if or a trailing && or ||.

            1. 3

              Thanks. I love sharing and learning tips like this; bash is such an essential skill.

            2. 5

              I’d say -eu is the bare minimum.

            3. 4

              Instead of dealing with the weirdness of -e and -u, pipefail, you could just…. you know check the failure conditions yourself.

              for pipefail -> bash sets an array called PIPESTATUS with all the exit codes of foregrounded pipelines. for set -e -> many programs can return differing exit codes and to know if it actually failed will likely require actually checking the value of $? or just using if statements. for set -u -> even in the article posted, you’re still treating unset variables as zero length strings, the only difference now is you added a new expansion to make it not fail for dubious reasons.

              also see: http://mywiki.wooledge.org/BashFAQ/105 specifically:

              “These rules are extremely convoluted, and they still fail to catch even some remarkably simple cases. Even worse, the rules change from one Bash version to another, as Bash attempts to track the extremely slippery POSIX definition of this “feature”. When a SubShell is involved, it gets worse still – the behavior changes depending on whether Bash is invoked in POSIX mode. Another wiki has a page that covers this in more detail. Be sure to check the caveats.”

              set -e is an anti feature.

              1. 3

                I like to expose the -x flag via an env variable. If someone has $DEBUG set, most of my scripts do -x. Which is exposed via the help I include.

                Pipefail can have some side effects you might not notice. Or at least, be harder to debug.

                1. 2

                  Quite useful! I always use -e, but have avoided -u since my scripts tend to provide lots of optional env vars; I’m not too familiar with the many cryptic sigils that bash allows inside ${}, but I’ll try to remember :- (mnemonic “that Prolog thing”) for giving default values so that I can start using -u by default.

                  1. 2

                    I really liked the u option and went to check my scripts only to find out that I’ve been using it for quite a while now in set -euo pipefail. E, OTOH, I had no idea about and is very interesting.

                    1. 2

                      I usually activate the -x flag when running the script interactively

                      if [[ -t 2 ]]; then
                         set -x