aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_notes/bash.html
diff options
context:
space:
mode:
Diffstat (limited to '_notes/bash.html')
-rw-r--r--_notes/bash.html184
1 files changed, 184 insertions, 0 deletions
diff --git a/_notes/bash.html b/_notes/bash.html
new file mode 100644
index 0000000..c401522
--- /dev/null
+++ b/_notes/bash.html
@@ -0,0 +1,184 @@
+---
+title: bash
+subtitle: best practices
+layout: nosidebar
+links:
+ - {rel: stylesheet, href: 'assets/css/guides.css'}
+features:
+ - title: Script header
+ topics:
+ - do:
+ - |
+ #!/usr/bin/env bash
+
+ set -o errexit -o nounset -o pipefail
+ shopt -s inherit_errexit lastpipe
+ dont:
+ - |
+ #!/bin/sh -e
+ - title: Arrays
+ topics:
+ - title: Declaration
+ do:
+ - |
+ local -a xs=()
+ declare -a xs=()
+ local -A xs=()
+ declare -A xs=()
+ dont:
+ - |
+ local -a xs
+ declare -a xs
+ local -A xs
+ declare -A xs
+
+ # Doesn't work with nounset:
+ echo "${#xs[@]}"
+ - title: Expansion
+ do:
+ - |
+ func ${arr[@]+"${arr[@]}"}
+ dont:
+ - |
+ # Doesn't work with nounset:
+ func "${arr[@]}"
+ - |
+ # Expands to 0 arguments instead of 1:
+ declare -a arr=('')
+ func "${arr[@]+"${arr[@]}"}"
+ - title: unset
+ do:
+ - |
+ unset -v 'arr[x]'
+ unset -v 'arr[$i]'
+ dont:
+ - |
+ # May break due to globbing:
+ unset -v arr[x]
+ # In addition, possible quoting problem:
+ unset -v arr[$i]
+ # Doesn't work for some reason:
+ unset -v 'arr["x"]'
+ unset -v 'arr["]"]'
+ # Also rejected:
+ unset -v 'arr["$i"]'
+
+ # An insightful discussion on the topic:
+ # https://lists.gnu.org/archive/html/help-bash/2016-09/msg00020.html
+ - title: errexit
+ topics:
+ - title: Command substitution
+ do:
+ - |
+ shopt -s inherit_errexit
+
+ foo() { echo foo ; }
+ bar() { false ; echo bar >&2 ; }
+
+ output="$( bar )"
+ foo "$output"
+
+ # If inherit_errexit is unavailable, you can do
+ #output="$( set -e; bar )"
+ dont:
+ - |
+ foo() { echo foo ; }
+ bar() { false ; echo bar >&2 ; }
+
+ # This will print both "foo" and "bar":
+ foo "$( bar )"
+ # This will also print "foo":
+ foo "$( false )"
+ - |
+ foo() { echo foo ; }
+ bar() { false ; echo bar >&2 ; }
+
+ # This will still print both "foo" and "bar".
+ output="$( bar )"
+ foo "$output"
+
+ # This won't print anything.
+ output="$( false )"
+ foo "$output"
+ - title: Process substitution
+ do:
+ - |
+ shopt -s lastpipe
+
+ result=()
+ cmd | while IFS= read -r line; do
+ result+=("$( process_line "$line" )")
+ done
+ dont:
+ - |
+ # Without lastpipe, the loop is executed is a subshell,
+ # and the array will be empty:
+ result=()
+ cmd | while IFS= read -r line; do
+ result+=("$( process_line "$line" )")
+ done
+ - |
+ # errexit doesn't work for <( cmd ) no matter what:
+ while IFS= read -r line; do
+ process_line "$line"
+ done < <( cmd )
+ # This will be printed even if cmd fails:
+ echo 'should never see this'
+ - |
+ # This breaks if $output contains the \0 byte:
+ output="$( cmd )"
+
+ while IFS= read -r line; do
+ process_line "$line"
+ done <<< "$output"
+ - title: Functions
+ do:
+ - |
+ foo() { false ; echo foo >&2 ; }
+
+ foo
+ echo ok
+ dont:
+ - |
+ foo() { false ; echo foo >&2 ; }
+
+ # This will print "foo" no matter what.
+ if foo; then
+ echo ok
+ fi
+
+ # Same below.
+ foo && echo ok
+ foo || echo fail
+
+ # It currently appears to be completely impossible to
+ # execute a function inside a conditional with errexit
+ # enabled. Therefore, you should try to avoid this
+ # whenever possible.
+---
+{% for feature in page.features %}
+ <h2>{{ feature.title }}</h2>
+ {% for topic in feature.topics %}
+ {% if topic.title %}
+ <h3>{{ topic.title }}</h3>
+ {% endif %}
+ <div class="row">
+ <div class="col-md-6">
+ {% for guide in topic.do %}
+ <div class="pre_container pre_do">
+ {% highlight bash %}{{ guide }}{% endhighlight %}
+ <div class="pre_mark"><span class="glyphicon glyphicon-ok"></span></div>
+ </div>
+ {% endfor %}
+ </div>
+ <div class="col-md-6">
+ {% for guide in topic.dont %}
+ <div class="pre_container pre_dont">
+ {% highlight bash %}{{ guide }}{% endhighlight %}
+ <div class="pre_mark"><span class="glyphicon glyphicon-remove"></span></div>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ {% endfor %}
+{% endfor %}