-
Notifications
You must be signed in to change notification settings - Fork 0
/
bash_learning_group.bashpresent
402 lines (360 loc) · 9.81 KB
/
bash_learning_group.bashpresent
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
#!/bin/bash
function header() {
echo
args_or_stdin "$@" | bigger | bold
line "$COLUMNS" '-' | bold | black
echo
}
function - () {
linewrap "⠀• $*"
echo
}
function codeblock() {
(
IFS=''
inputmargin="undefined"
line "$((COLUMNS-6))" ' '
COLUMNS=$((COLUMNS-6)) linewrap "$@" | while read line; do
if [[ "${inputmargin}" == "undefined" ]]; then
inputmargin="${line%%[^ ]*}"
fi
echo "${line#${inputmargin}}"
done
echo
) | margin_left 2 | bold | green | box
}
function ci() {
# code inline
green "$@" | bold
}
function param() {
underline "$@" | ci
}
function slide_title() {
pad_on_bottom $(((LINES-6)/2)) ' '
bigger "Bash Scripting" | bold | center
echo
fullwidth "Evan Krall" | bold | blue | center
}
function slide_two() {
header "Who am I"
- Systems team
- Bash scripting for \>10 years
}
function slide_three() {
header "Outline"
- Basic grammar
- Expansion order
- Arrays
- Scoping and subshells
- Testing
}
function slide_simplecommand() {
header "Simple commands"
- Optional list of variable assignments
- blank-separated words and redirections
codeblock <<"END"
echo "foo" >foo.txt
rm -rf /
grep -r 'hello' . 2>/dev/null
PYTHONPATH="$HOME/pg/yelp-main" python blah.py
END
}
function slide_pipeline() {
header "Pipelines"
- A pipeline is a sequence of one or more commands separated by the pipe character: $(ci \|)
echo
center "[$(ci time) [$(ci -p)]] [ "$(ci '!')" ] $(param command) [ $(ci "| $(param command2)") ... ]"
}
function slide_lists() {
header "Lists"
- "Sequence of pipelines, separated by $(ci ';'), $(ci '&'), $(ci '||'), $(ci '&&')"
- "If a command ends in $(ci '&'), the shell executes the command in the background in a subshell"
- Return status of a list is the exit status of the last command executed
}
function slide_lists_contd() {
header "Lists (cont'd)"
- $(ci '||') and $(ci '&&') are lazy-evaluated
- Equal precedence.
codeblock <<"END"
$ true && echo "hi"
hi
$ false && echo "hi"
$ false && echo "true" || echo "false"
false
END
}
function slide_if() {
header "if - elif - else - fi"
codeblock <<END
if $(param list); then
$(param list)
elif $(param list); then
$(param list)
else
$(param list)
fi
END
}
function slide_while() {
header "while - do - done"
codeblock <<END
while $(param list1); do
$(param list2)
done
END
- while $(param list1) returns zero, executes $(param list2)
}
function slide_for() {
header "for - in - do - done"
codeblock <<END
for $(param name) in $(param word); do
$(param list)
done
END
- The list of words following $(ci in) is expanded, generating a list of items. \
The variable $(param name) is set to each element of this list in turn, and\
$(param list) is executed each time.
}
function slide_functions() {
header "function definitions"
echo
center "[$(ci function)] $(param name) [$(ci "()")] $(param compound-command)"
echo
- $(ci function) and $(ci '()') are optional, but you must have at least one.
codeblock <<END
# These are equivalent:
function foo() {
...
}
function foo {
...
}
foo() {
...
}
END
}
function slide_functions_contd() {
header "function definitions (cont'd)"
- If you use $(ci '()') instead of $(ci '{}'), the contents of the function get executed in a subshell.
- You can also specify a redirection for the whole function:
codeblock <<END
function foo() {
echo "blah"
} >/dev/null
$ foo
$
END
- Return code is exit code of last command executed.
}
function slide_expansion() {
header "Expansion"
- Brace expansion
- Tilde expansion
- Parameter and variable expansion
- Command substitution
- Arithmetic expansion
- Word splitting
- Pathname expansion
}
function slide_brace_expansion() {
header "Brace expansion"
codeblock <<END
$ echo a{d,c,b}e
ade ace abe
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
$ echo {01..10} # bash 4
01 02 03 04 05 06 07 08 09 10
$ echo {01..10} # bash 3
1 2 3 4 5 6 7 8 9 10
$ echo \'{a..e}\'
'a' 'b' 'c' 'd' 'e'
$ echo {0,1}{a,b}
0a 0b 1a 1b
END
}
function slide_tilde_expansion() {
header "Tilde expansion"
- Expands to \$HOME, or someone else\'s home dir.
codeblock <<"END"
$ echo ~
/Users/krall
$ echo ~abakun # on a dev machine
/nail/home/abakun
END
}
function slide_parameter_expansion() {
header "Parameter expansion"
codeblock <<"END"
$ var="Bash scripting is cool"
$ echo $var
Bash scripting is cool
$ echo ${var}
Bash scripting is cool
$ echo ${var#* } -- ${var##* }
scripting is cool -- cool
$ echo ${var% *} -- ${var%% *}
Bash scripting is -- Bash
END
}
function slide_parameter_expansion_2() {
header "Parameter expansion (cont'd)"
codeblock <<"END"
$ var="Bash scripting is cool"
$ echo ${var:10}
ting is cool
$ echo [${var:10:4}]
[ting]
$ echo ${var/ /_}
Bash_scripting is cool
$ echo ${var// /_}
Bash_scripting_is_cool
END
}
function slide_command_substitution() {
header "Command substitution"
center "$(ci "\$\($(param command)\)")"
center or
center "$(ci "\`$(param command)\`")"
echo
- Runs $(param command), replaces the command substitution with the standard output of the command
- Trailing newlines are deleted.
codeblock <<"END"
$ echo $(echo foo)
foo
$ echo The last word in the dictionary is $(tail -n1 /usr/share/dict/words)
The last word in the dictionary is Zyzzogeton
END
}
function slide_arithmetic() {
header "Arithmetic Expansion"
echo
center "$(ci '$(('"$(param expression)"'))')"
echo
codeblock <<"END"
$ echo $((2+2))
4
$ foo=3; echo $((2+foo)); echo $((2+$foo))
5
5
END
}
function slide_word_splitting() {
header "Word splitting"
- The shell scans the results of parameter expansion, command substitution,\
and arithmetic expansion that $(bold "did not occur within double quotes") for word splitting.
codeblock <<"END"
$ function show_words() { for word in "$@"; do echo -n "'${word}' "; done; echo; }
$ show_words hi hello
'hi' 'hello'
$ show_words "hi hello"
'hi hello'
$ var="Bash scripting is cool"
$ show_words $var
'Bash' 'scripting' 'is' 'cool'
$ show_words "$var"
'Bash scripting is cool'
END
}
function slide_pathname_expansion() {
header "Pathname expansion"
- After word splitting, bash scans each word for the characters $(ci \*), $(ci \?), and \
$(ci \[). If one of these characters appears, then the word is regarded as a pattern, and \
replaced with an alphabetically sorted list of file names matching the pattern.
codeblock <<"END"
$ mkdir demo; cd demo; touch foo.txt bar.txt baz.txt
$ echo *
bar.txt baz.txt foo.txt
$ echo bar*
bar.txt
$ echo ba?.txt
bar.txt baz.txt
$ foo='*'
$ echo "$foo" versus $foo
* versus bar.txt baz foo.txt
END
}
function slide_arrays() {
header "Arrays"
- Arrays in bash are one-dimensional sparse arrays of strings
codeblock <<"END"
$ var="One"
$ var[1]="Two"
$ echo $var
One
$ echo $var[1] versus ${var[1]}
One[1] versus Two
$ show_words "${var[*]}"
'One Two'
$ show_words "${var[@]}"
'One' 'Two'
END
}
function slide_arrays_2() {
header "Arrays (cont'd)"
codeblock <<"END"
$ array=("one" "two" "third word")
$ show_words ${var[*]}
'one' 'two' 'third' 'word'
$ show_words "${var[*]}"
'one two third word'
$ show_words "${var[@]}"
'one' 'two' 'third word'
END
}
function slide_positional_parameters() {
header "Positional Parameters"
- $(ci \$0) through $(ci \$9), $(ci \${10}) ...
- Special parameters $(ci '$*') and $(ci '$@') evaluate to all arguments.
codeblock <<"END"
$ function switch() { echo "$2" "$1"; }
$ switch foo bar
bar foo
$ function colons() { local IFS=':'; echo "$*"; }
$ colons hi hello
hi:hello
END
}
function slide_scope() {
header "Scope"
- Generally global to your interpreter
- Can be made local to a function with the $(ci local) keyword
codeblock <<"END"
$ function foo() { local blah="hi"; echo $blah; }
$ function bar() { blah="hello"; echo $blah; }
$ blah=''
$ foo
hi
$ bar
hello
$ echo $blah
hello
END
}
function slide_scope_subshells() {
header "Scope (subshells)"
- Commands in a subshell executes in a new interpreter
codeblock <<"END"
$ function baz() ( blah="hello"; echo $blah; )
$ blah=''
$ baz
hello
$ echo $blah
$
END
}
function slide_testing() {
header Testing
- You can, in fact, write tests for bash scripts.
- It\'s just tricky, since many bash scripts have side effects.
- It helps if you break your code into small, side-effect-free functions.
codeblock <<"END"
# Let your code be sourced safely by including a block like this:
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
# not being sourced.
main "$@"
fi
END
}