aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_notes/bash.html
blob: ea0cb8a0c982ddfc0972e862b482ebfb6c5000e5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
---
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 %}
  <h2>{{ feature.title }}</h2>
  {% for topic in feature.topics %}
    <h3>{{ topic.title }}</h3>
    <div class="row">
      <div class="col-md-6">
        {% for guide in topic.do %}
          {% highlight bash %}{{ guide }}{% endhighlight %}
        {% endfor %}
      </div>
      <div class="col-md-6">
        {% for guide in topic.dont %}
          {% highlight bash %}{{ guide }}{% endhighlight %}
        {% endfor %}
      </div>
    </div>
  {% endfor %}
{% endfor %}