blob: cedfb4361004788fe57e7bd340b35ef89baaef8f (
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
---
title: Bash
subtitle: best practices
layout: plain
links:
- {rel: stylesheet, href: 'assets/css/bash.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 %}
|