diff options
author | Lars Wirzenius <lwirzenius@wikimedia.org> | 2020-05-15 13:50:58 +0300 |
---|---|---|
committer | Lars Wirzenius <lwirzenius@wikimedia.org> | 2020-05-15 13:50:58 +0300 |
commit | 051426cfd7f8a66a78b02cc34da3f9e2e2372d13 (patch) | |
tree | df99de8b38ff880ea0c32f2fd96f7a5342c810ae | |
parent | 3af2dc7ea57e4f3956090baa8b7596687ea9b90a (diff) | |
download | wmf-talks-051426cfd7f8a66a78b02cc34da3f9e2e2372d13.tar.gz |
Add: talk on shell scripting
-rwxr-xr-x | shell-param.sh | 18 | ||||
-rw-r--r-- | shell-temp.sh | 15 | ||||
-rw-r--r-- | shell.md | 274 |
3 files changed, 307 insertions, 0 deletions
diff --git a/shell-param.sh b/shell-param.sh new file mode 100755 index 0000000..67626bb --- /dev/null +++ b/shell-param.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -eu + +echo dollar-at +for x in $@; do echo "<$x>"; done + +echo +echo dollar-at in quotes +for x in "$@"; do echo "<$x>"; done + +echo +echo dollar-star +for x in $@; do echo "<$x>"; done + +echo +echo dollar-star in quotes +for x in "$@"; do echo "<$x>"; done diff --git a/shell-temp.sh b/shell-temp.sh new file mode 100644 index 0000000..7fd1d52 --- /dev/null +++ b/shell-temp.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -eu + +cleanup() { + rm -rf "$tempdir" +} + + +tempdir="$(mktemp -d)" +trap cleanup EXIT + + +echo foo > "$tempdir/foo.txt" +echo "$tempdir" diff --git a/shell.md b/shell.md new file mode 100644 index 0000000..2996d68 --- /dev/null +++ b/shell.md @@ -0,0 +1,274 @@ +# Introduction + +* Shell scripting is easy, but also risky +* So, so easy +* So, so risky +* Interactive use is off-topic for this talk + +----------------------------------------------------------------------------- + +# Hashbang + +OK, less powerful than bash, but more portable: + +~~~sh +#!/bin/sh +~~~ + +OK on Linux, not everywhere: + +~~~sh +#!/bin/bash +~~~ + +Portable, but might invoke a different bash: + +~~~sh +#!/usr/bin/env bash +~~~ + +----------------------------------------------------------------------------- + +# Error prevention and handling + +**Always, always, without exception, use this:** + +~~~sh +set -eu +~~~ + +If it's OK for a command to fail: + +~~~sh +this.may.fail || true +~~~ + +If using bash, optionally also use these: + +~~~sh +set -o pipefail +set -o noclobber +~~~ + +----------------------------------------------------------------------------- + +# No options in hashbang + +~~~sh +#!/bin/sh +set -eu +~~~ + +**Never, never, ever:** + +~~~sh +#!/bin/sh -eu +~~~ + +Because: + +~~~sh +$ sh -x foo.sh +~~~ + +-x is a useful debugging option for sh. + + +----------------------------------------------------------------------------- + +# Escaping, quoting, variable expansion + +**Always, always** quote all variable expansions: + +~~~{.sh .numberLines} +$ foo="/ home/liw" +$ print-argv rm -f $foo +[0]: /usr/bin/print-argv +[1]: rm +[2]: -f +[3]: / +[4]: home/liw +$ print-argv rm -f "$foo" +[0]: /usr/bin/print-argv +[1]: rm +[2]: -f +[3]: / home/liw +$ +~~~ + +_"If your script needs to use $, switch to Python/Ruby/Perl"_—liw + +----------------------------------------------------------------------------- + +# print-argv + +~~~{.python .numberLines} +#!/usr/bin/python3 +import sys +for i, arg in enumerate(sys.argv): + sys.stdout.write('[%d]: %s\n' % (i, arg)) +~~~ + +----------------------------------------------------------------------------- + +# Use $(...) instead of backticks. But be careful. + +~~~sh +$ touch 'foo bar' +$ print-argv foo* +[0]: /usr/bin/print-argv +[1]: foo bar +$ print-argv $(ls foo*) +[0]: /usr/bin/print-argv +[1]: foo +[2]: bar +$ print-argv "$(ls foo*)" +[0]: /usr/bin/print-argv +[1]: foo bar +$ +~~~ + +----------------------------------------------------------------------------- + +# Parameter expansion: $@ vs @* + +~~~{.sh .numberLines} +#!/bin/sh +set -eu + +echo dollar-at +for x in $@; do echo "<$x>"; done + +echo; echo dollar-at in quotes +for x in "$@"; do echo "<$x>"; done + +echo; echo dollar-star +for x in $@; do echo "<$x>"; done + +echo; echo dollar-star in quotes +for x in "$@"; do echo "<$x>"; done +~~~ + +----------------------------------------------------------------------------- + +~~~{.sh .numberLines} +$ touch 'foo bar' +$ ./shell-param.sh foo* +dollar-at +<foo> +<bar> + +dollar-at in quotes +<foo bar> + +dollar-star +<foo> +<bar> + +dollar-star in quotes +<foo bar> +$ +~~~ + +----------------------------------------------------------------------------- + +**Always, always, without exception** use `"$@"` + +**Never, never, ever** use `$@` or `$*` without quotes +exception granted if you can explain why it's safe in a specific +case, and you do it in a comment + +but use Python, Ruby, or Perl instead, seriously + +----------------------------------------------------------------------------- + +# Command line option parsing in shell + +Don't. Use Python, Ruby, or Perl instead. + + +----------------------------------------------------------------------------- + +# Shell functions + +~~~sh +foo() { + local arg1 + arg1="$1" +} +~~~ + +Avoid: `local arg1="$1"` +because it interacts badly with pipefail. + +Avoid: `function foo {}` +because that's an unnecessary bashism. + +----------------------------------------------------------------------------- + +# Temporary files + +~~~{.sh .numberLines} +#!/bin/sh + +set -eu + +cleanup() { + rm -rf "$tempdir" +} + + +tempdir="$(mktemp -d)" +trap cleanup EXIT + + +echo foo > "$tempdir/foo.txt" +echo "$tempdir" +~~~ + +----------------------------------------------------------------------------- + +~~~{.sh .numberLines} +$ mkdir t +$ TMPDIR=t ./shell-temp.s +t/tmp.EgiOqQ9SAU +$ find t +t +$ +~~~ + +----------------------------------------------------------------------------- + +# Summary + +* Know the rules. +* The rules are intricate and hard to remember all the time. +* You _will_ fail. +* Give up and use a better language. + +----------------------------------------------------------------------------- + +# Further reading + +<https://www.davidpashley.com/articles/writing-robust-shell-scripts/> + +<https://www.shellcheck.net/> + +----------------------------------------------------------------------------- + +# Legalese + +Copyright 2020 Wikimedia Foundation + +This content is licensed under the Creative Commons +Attribution-ShareAlike 4.0 International ([CC BY-SA 4.0][]) licence. + +[CC BY-SA 4.0]: https://creativecommons.org/licenses/by-sa/4.0/ + + +--- +title: "Shell scripting" +subtitle: "some opinionated dos and dont's" +author: "Lars Wirzenius / Wikimedia Foundation" +date: "Version for 2020-05-18" +... |