--- title: Bash subtitle: best practices layout: plain features: - title: Arrays topics: - title: Declaration do: - | local -a xs=() declare -a xs=() local -A xs=() declare -A xs=() # Works with nounset: echo "${#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[@]}" # Doesn't work properly with `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: - | # Without this, bar will be executed w/ errexit disabled! shopt -s inherit_errexit bar() { false echo 'should never see this' >&2 } bar_output="$( bar )" foo "$bar_output" dont: - | bar() { false echo 'should never see this' >&2 } # Even with errexit, foo will still get executed. # More than that, the script will print 'should never see this'! foo "$( bar )" - title: Process substitution do: - | shopt -s lastpipe command | while IFS= read -r line; do process_line "$line" done dont: - | # Without lastpipe, you cannot pipe into read: command | while IFS= read -r line; do process_line "$line" done - | # errexit doesn't work here no matter what: while IFS= read -r line; do process_line "$line" done < <( command ) echo 'should never see this' - | # This would break if $output contains the \0 byte: output="$( command )" while IFS= read -r line; do process_line "$line" done <<< "$output" - title: Functions do: - | foo() { false echo 'should never see this' >&2 } foo echo ok dont: - | # foo will still print 'should never see this'. if foo; then echo ok fi # Same below. foo && echo ok foo || echo ok --- {% for feature in page.features %}