Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should bash strict mode be recommended as good practice? #30

Open
peterjc opened this issue Nov 25, 2015 · 14 comments
Open

Should bash strict mode be recommended as good practice? #30

peterjc opened this issue Nov 25, 2015 · 14 comments

Comments

@peterjc
Copy link

peterjc commented Nov 25, 2015

Should bash strict mode be recommended as good practice? See http://redsymbol.net/articles/unofficial-bash-strict-mode/ which uses:

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

Personally I use set -e most heavily, and generally just use the one line set -euo pipefail after the hash-bang.

Originally raised as swcarpentry/shell-novice#251 but we agreed it was too advanced for the shell novice lesson.

@kynan
Copy link
Contributor

kynan commented Dec 1, 2015

👍 I think that's definitely appropriate for an intermediate audience.

@lexnederbragt
Copy link

👍 from me too. Makes me wonder whether there could be a shell-scripting lesson here as well, including this, using functions, if...then statements.

@gvwilson
Copy link
Contributor

gvwilson commented Dec 2, 2015 via email

@lexnederbragt
Copy link

I completely agree, and I keep saying this to many people on our lab, but getting them to give up the (false) comfort of their bash skills and scripts, and take a course in python/R/whatever that gets them to the same level of comfort, is not something I am very successful with (I need more power ;-) ).

Maybe a lesson on 'if you (would like to) do this in a shell script, the equivalent python script would look like this'?

@kynan
Copy link
Contributor

kynan commented Dec 12, 2015

@gvwilson @lexnederbragt Agree with you in principle, however there are many use cases where shell scripts are still the better choice: for running a series of commands (executables) you should really not use Python (in particular not os.system!) or another high level language. For that a bash script with set -euo pipefail is the way to go.

@lexnederbragt
Copy link

Hmmm... I am more and more convinced that a Makefile is the better way to go in such a case. But that has another set of drawbacks: not easy to learn, less transparent what is being run...

@kynan
Copy link
Contributor

kynan commented Dec 20, 2015

Sure, as soon as it gets slightly more complex and you have interdependencies a Makefile is definitely superior. But there is that narrow use case for bash scripts and for that imho strict mode is very important.

@gdevenyi
Copy link
Collaborator

If we recommend strict mode, we should note it could break some workflows.

I recently ran into an issue where I was some text manipulation in a subshell that can fail which was okay for the toolchain, but when I added strict the toolchain would exit if that subshell call failed.

@gvwilson When you work on a toolchain that exclusively relies on manipulating files and chaining together other command line tools, what do you suggest if not bash?

@kynan
Copy link
Contributor

kynan commented Feb 21, 2016

@gdevenyi You can always append || true to any command to ignore a specific failure.

@jttkim
Copy link

jttkim commented Feb 22, 2016

Getting back to @peterjc's initial comment of using set -e, it seems to me that discussing the elements of the "unofficial strict mode" individually may make sense. Personally I

  • recommend -e and -o pipefail unreservedly,
  • am generally in favour of -u as well, but would expect that this may result in learners finding that numerous examples / tutorials / code snippets don't seem to work for them, so people need to be prepared a bit,
  • am not so sure about the IFS setting -- interfering with the scan / parse process like that doesn't seem right to me, although I have sympathy for the motivation of trying to write scripts that can deal with file names containing spaces without running into trouble due to tokenising these.

@HaleTom
Copy link

HaleTom commented Feb 19, 2017

Also consider shopt -s failglob

@CristianCantoro
Copy link

I would recommend this version:

#!/usr/bin/env bash

SOURCED=false && [ "$0" = "$BASH_SOURCE" ] || SOURCED=true

if ! $SOURCED; then
  set -euo pipefail
  IFS=$'\n\t'
fi

(read more)

In this way you can safely source the script, if needed, without polluting your shell.

@ssbarnea
Copy link

@CristianCantoro Interesting idea but I see two problems with it: it may fail if run with non bash shell or if you already had set -u enabled before calling it, as BASH_SOURCE would not be defined. I guess is going into the right direction anyway.

@CristianCantoro
Copy link

CristianCantoro commented Dec 29, 2017

@ssbarnea to be fair this is the bash strict mode, so I would say that using bash is implied 😉 (I use zsh as my shell, but I write almost all of my shell scripts in bash).

However, you are absolutely right, I didn't notice this issue it until because it manifests itself only if you source the script directly from a non-bash shell and you have set -u either before in the script or in your shell.

If you are using bash, BASH_SOURCE is a variable, so it is available and the script does not fail even with set -u.

This would be a fix:

#!/usr/bin/env bash

SOURCED=true
if [ ! -z "${BASH_SOURCE+x}" ]; then
  SOURCED=false && [ "$0" = "$BASH_SOURCE" ] || SOURCED=true
fi

if ! $SOURCED; then
  set -euo pipefail
  IFS=$'\n\t'
fi

A little bit more verbose, and it still does not support other shells, though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants