--- title: Bash subtitle: best practices layout: plain --- Arrays ------ ### Declaration
```bash local -a xs=() declare -a xs=() local -A xs=() declare -A xs=() # Works with nounset: echo "${#xs[@]}" ```
```bash local -a xs declare -a xs local -A xs declare -A xs # Doesn't work with nounset: echo "${#xs[@]}" ```
### Expansion
```bash func ${arr[@]+"${arr[@]}"} ```
```bash # Doesn't work with nounset: func "${arr[@]}" # Doesn't work properly with `declare -a arr=('')`: func "${arr[@]+"${arr[@]}"}" ```
### `unset`
```bash unset -v 'arr[x]' unset -v 'arr[$i]' ```
```bash # 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 ```
`errexit` --------- I hate this feature, and I especially hate people who prefer "standards" over useful behaviour. ### Command substitution
```bash # 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" ```
```bash 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 )" ```
### Process substitution
```bash shopt -s lastpipe command | while IFS= read -r line; do process_line "$line" done ```
```bash # Without lastpipe, you cannot pipe into read: command | while IFS= read -r line; do process_line "$line" done ``` ```bash # errexit doesn't work here no matter what: while IFS= read -r line; do process_line "$line" done < <( command ) echo 'should never see this' ``` ```bash # This would break if $output contains the \0 byte: output="$( command )" while IFS= read -r line; do process_line "$line" done <<< "$output" ```
### Functions
```bash foo() { false echo 'should never see this' >&2 } foo echo ok ```
```bash # foo will still print 'should never see this'. if foo; then echo ok fi # Same below. foo && echo ok foo || echo ok ```