readability-cli 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
guides/shellguide.md ADDED
@@ -0,0 +1,1343 @@
1
+ <!--
2
+ AUTHORS:
3
+ Prefer only GitHub-flavored Markdown in external text.
4
+ See README.md for details.
5
+ -->
6
+
7
+ # Shell Style Guide
8
+
9
+
10
+ Authored, revised and maintained by many Googlers.
11
+
12
+ ## Table of Contents
13
+
14
+ Section | Contents
15
+ ------------------------------------------------------------------------------------ | --------
16
+ [Background](#s1-background) | [Which Shell to Use](#s1.1-which-shell-to-use) - [When to use Shell](#s1.2-when-to-use-shell)
17
+ [Shell Files and Interpreter Invocation](#s2-shell-files-and-interpreter-invocation) | [File Extensions](#s2.1-file-extensions) - [SUID/SGID](#s2.2-suid-sgid)
18
+ [Environment](#s3-environment) | [STDOUT vs STDERR](#s3.1-stdout-vs-stderr)
19
+ [Comments](#s4-comments) | [File Header](#s4.1-file-header) - [Function Comments](#s4.2-function-comments) - [Implementation Comments](#s4.3-implementation-comments) - [TODO Comments](#s4.4-todo-comments)
20
+ [Formatting](#s5-formatting) | [Indentation](#s5.1-indentation) - [Line Length and Long Strings](#s5.2-line-length-and-long-strings) - [Pipelines](#s5.3-pipelines) - [Control Flow](#s5.4-control-flow) - [Case statement](#s5.5-case-statement) - [Variable expansion](#s5.6-variable-expansion) - [Quoting](#s5.7-quoting)
21
+ [Features and Bugs](#s6-features-and-bugs) | [ShellCheck](#s6.1-shellcheck) - [Command Substitution](#s6.2-command-substitution) - [Test, `[… ]`, and `[[… ]]`](#s6.3-tests) - [Testing Strings](#s6.4-testing-strings) - [Wildcard Expansion of Filenames](#s6.5-wildcard-expansion-of-filenames) - [Eval](#s6.6-eval) - [Arrays](#s6.7-arrays) - [Pipes to While](#s6.8-pipes-to-while) - [Arithmetic](#s6.9-arithmetic) - [Aliases](#s6.10-aliases)
22
+ [Naming Conventions](#s7-naming-conventions) | [Function Names](#s7.1-function-names) - [Variable Names](#s7.2-variable-names) - [Constants and Environment Variable Names](#s7.3-constants-and-environment-variable-names) - [Source Filenames](#s7.4-source-filenames) - [Use Local Variables](#s7.5-use-local-variables) - [Function Location](#s7.6-function-location) - [main](#s7.7-main)
23
+ [Calling Commands](#s8-calling-commands) | [Checking Return Values](#s8.1-checking-return-values) - [Builtin Commands vs. External Commands](#s8.2-builtin-commands-vs-external-commands)
24
+ [When in Doubt: Be Consistent](#s9-conclusion) |
25
+
26
+ <a id="s1-background"></a>
27
+
28
+ ## Background
29
+
30
+
31
+ <a id="s1.1-which-shell-to-use"></a>
32
+
33
+ ### Which Shell to Use
34
+
35
+ Bash is the only shell scripting language permitted for executables.
36
+
37
+ Executables must start with `#!/bin/bash` and minimal flags. Use `set` to set
38
+ shell options so that calling your script as `bash script_name` does not break
39
+ its functionality.
40
+
41
+ Restricting all executable shell scripts to *bash* gives us a consistent shell
42
+ language that's installed on all our machines. In particular, this means there
43
+ is generally no need to strive for POSIX-compatibility or otherwise avoid
44
+ "bashisms".
45
+
46
+ The only exception to the above is where you're forced to by whatever you're
47
+ coding for. For example some legacy operating systems or constrained execution
48
+ environments may require plain Bourne shell for certain scripts.
49
+
50
+ <a id="s1.2-when-to-use-shell"></a>
51
+
52
+ ### When to use Shell
53
+
54
+ Shell should only be used for small utilities or simple wrapper
55
+ scripts.
56
+
57
+ While shell scripting isn't a development language, it is used for
58
+ writing various utility scripts throughout Google. This style guide
59
+ is more a recognition of its use rather than a suggestion that it be
60
+ used for widespread deployment.
61
+
62
+ Some guidelines:
63
+
64
+ * If you're mostly calling other utilities and are doing relatively little
65
+ data manipulation, shell is an acceptable choice for the task.
66
+ * If performance matters, use something other than shell.
67
+ * If you are writing a script that is more than 100 lines long, or that uses
68
+ non-straightforward control flow logic, you should rewrite it in a more
69
+ structured language *now*. Bear in mind that scripts grow. Rewrite your
70
+ script early to avoid a more time-consuming rewrite at a later date.
71
+ * When assessing the complexity of your code (e.g. to decide whether to switch
72
+ languages) consider whether the code is easily maintainable by people other
73
+ than its author.
74
+
75
+ <a id="s2-shell-files-and-interpreter-invocation"></a>
76
+
77
+ ## Shell Files and Interpreter Invocation
78
+
79
+ <a id="s2.1-file-extensions"></a>
80
+
81
+ ### File Extensions
82
+
83
+ Executables should have a `.sh` extension or no extension.
84
+
85
+ - If the executable will have a build rule that renames the source file
86
+ then prefer to use a `.sh` extension.
87
+ This enables you to use the recommended naming convention, with a source
88
+ file like `foo.sh` and a build rule named `foo`.
89
+ - If the executable will be added directly to the user's `PATH`, then prefer
90
+ to use no extension. It is not necessary to know what language a program is
91
+ written in when executing it and shell doesn't require an extension so we
92
+ prefer not to use one for executables that will be directly invoked by
93
+ users. At the same time, consider whether it is preferable to deploy the
94
+ output of a build rule rather than deploying the source file directly.
95
+ - If neither of the above apply, then either choice is acceptable.
96
+
97
+ Libraries must have a `.sh` extension and should not be executable.
98
+
99
+ <a id="s2.2-suid-sgid"></a>
100
+
101
+ ### SUID/SGID
102
+
103
+ SUID and SGID are *forbidden* on shell scripts.
104
+
105
+ There are too many security issues with shell that make it nearly
106
+ impossible to secure sufficiently to allow SUID/SGID. While bash does
107
+ make it difficult to run SUID, it's still possible on some platforms
108
+ which is why we're being explicit about banning it.
109
+
110
+ Use `sudo` to provide elevated access if you need it.
111
+
112
+ <a id="s3-environment"></a>
113
+
114
+ ## Environment
115
+
116
+ <a id="s3.1-stdout-vs-stderr"></a>
117
+
118
+ ### STDOUT vs STDERR
119
+
120
+ All error messages should go to `STDERR`.
121
+
122
+ This makes it easier to separate normal status from actual issues.
123
+
124
+ A function to print out error messages along with other status
125
+ information is recommended.
126
+
127
+ ```shell
128
+ err() {
129
+ echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
130
+ }
131
+
132
+ if ! do_something; then
133
+ err "Unable to do_something"
134
+ exit 1
135
+ fi
136
+ ```
137
+
138
+ <a id="s4-comments"></a>
139
+
140
+ ## Comments
141
+
142
+ <a id="s4.1-file-header"></a>
143
+
144
+ ### File Header
145
+
146
+ Start each file with a description of its contents.
147
+
148
+ Every file must have a top-level comment including a brief overview of
149
+ its contents. A
150
+ copyright notice
151
+ and author information are optional.
152
+
153
+ Example:
154
+
155
+ ```shell
156
+ #!/bin/bash
157
+ #
158
+ # Perform hot backups of Oracle databases.
159
+ ```
160
+
161
+ <a id="s4.2-function-comments"></a>
162
+
163
+ ### Function Comments
164
+
165
+ Any function that is not both obvious and short must have a function header
166
+ comment. Any function in a library must have a function header comment
167
+ regardless of length or complexity.
168
+
169
+ It should be possible for someone else to learn how to use your
170
+ program or to use a function in your library by reading the comments
171
+ (and self-help, if provided) without reading the code.
172
+
173
+ All function header comments should describe the intended API behaviour using:
174
+
175
+ * Description of the function.
176
+ * Globals: List of global variables used and modified.
177
+ * Arguments: Arguments taken.
178
+ * Outputs: Output to STDOUT or STDERR.
179
+ * Returns: Returned values other than the default exit status of the last
180
+ command run.
181
+
182
+ Example:
183
+
184
+ ```shell
185
+ #######################################
186
+ # Cleanup files from the backup directory.
187
+ # Globals:
188
+ # BACKUP_DIR
189
+ # ORACLE_SID
190
+ # Arguments:
191
+ # None
192
+ #######################################
193
+ function cleanup() {
194
+
195
+ }
196
+
197
+ #######################################
198
+ # Get configuration directory.
199
+ # Globals:
200
+ # SOMEDIR
201
+ # Arguments:
202
+ # None
203
+ # Outputs:
204
+ # Writes location to stdout
205
+ #######################################
206
+ function get_dir() {
207
+ echo "${SOMEDIR}"
208
+ }
209
+
210
+ #######################################
211
+ # Delete a file in a sophisticated manner.
212
+ # Arguments:
213
+ # File to delete, a path.
214
+ # Returns:
215
+ # 0 if thing was deleted, non-zero on error.
216
+ #######################################
217
+ function del_thing() {
218
+ rm "$1"
219
+ }
220
+ ```
221
+
222
+ <a id="s4.3-implementation-comments"></a>
223
+
224
+ ### Implementation Comments
225
+
226
+ Comment tricky, non-obvious, interesting or important parts of your
227
+ code.
228
+
229
+ This follows general Google coding comment practice. Don't comment
230
+ everything. If there's a complex algorithm or you're doing something
231
+ out of the ordinary, put a short comment in.
232
+
233
+ <a id="s4.4-todo-comments"></a>
234
+
235
+ ### TODO Comments
236
+
237
+ Use TODO comments for code that is temporary, a short-term solution, or
238
+ good-enough but not perfect.
239
+
240
+ This matches the convention in the [C++ Guide](https://google.github.io/styleguide/cppguide.html#TODO_Comments).
241
+
242
+
243
+ `TODO`s should include the string `TODO` in all caps, followed by the name,
244
+ e-mail address, or other identifier of the person with the best context about
245
+ the problem referenced by the `TODO`. The main purpose is to have a consistent
246
+ `TODO` that can be searched to find out how to get more details upon request. A
247
+ `TODO` is not a commitment that the person referenced will fix the problem. Thus
248
+ when you create a `TODO`, it is almost always your name that is given.
249
+
250
+ Examples:
251
+
252
+ ```shell
253
+ # TODO(mrmonkey): Handle the unlikely edge cases (bug ####)
254
+ ```
255
+
256
+ <a id="s5-formatting"></a>
257
+
258
+ ## Formatting
259
+
260
+ While you should follow the style that's already there for files that
261
+ you're modifying, the following are required for any new code.
262
+
263
+ <a id="s5.1-indentation"></a>
264
+
265
+ ### Indentation
266
+
267
+ Indent 2 spaces. No tabs.
268
+
269
+ Use blank lines between blocks to improve readability. Indentation is
270
+ two spaces. Whatever you do, don't use tabs. For existing files, stay
271
+ faithful to the existing indentation.
272
+
273
+ **Exception:** The only exception for using tabs is for the body of `<<-`
274
+ tab-indented
275
+ [here-document](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Documents).
276
+
277
+ <a id="s5.2-line-length-and-long-strings"></a>
278
+
279
+ ### Line Length and Long Strings
280
+
281
+ Maximum line length is 80 characters.
282
+
283
+ If you have to write literal strings that are longer than 80 characters, this
284
+ should be done with a
285
+ [here document](https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Documents)
286
+ or an embedded newline if possible.
287
+
288
+ Words that are longer than 80 chars and can't sensibly be split are ok, but
289
+ where possible these items should be on a line of their own, or factored into a
290
+ variable. Examples include file paths and URLs, particularly where
291
+ string-matching them (such as `grep`) is valuable for maintenance.
292
+
293
+ ```shell
294
+ # DO use 'here document's
295
+ cat <<END
296
+ I am an exceptionally long
297
+ string.
298
+ END
299
+
300
+ # Embedded newlines are ok too
301
+ long_string="I am an exceptionally
302
+ long string."
303
+
304
+ long_file="/i/am/an/exceptionally/loooooooooooooooooooooooooooooooooooooooooooooooooooong_file"
305
+
306
+ long_string_with_long_file="i am including an exceptionally \
307
+ /very/long/file\
308
+ in this long string."
309
+
310
+ # Long file converted into a shorter variable name with cleaner line breaking.
311
+ long_string_alt="i am an including an exceptionally ${long_file} in this long\
312
+ string"
313
+ ```
314
+
315
+ ```shell
316
+ # Just because a line contains an exception doesn't mean the rest of the
317
+ # line shouldn't be wrapped like usual.
318
+
319
+ bad_long_string_with_long_file="i am including an exceptionally /very/long/file in this long string."
320
+ ```
321
+
322
+ <a id="s5.3-pipelines"></a>
323
+
324
+ ### Pipelines
325
+
326
+ Pipelines should be split one per line if they don't all fit on one line.
327
+
328
+ If a pipeline all fits on one line, it should be on one line.
329
+
330
+ If not, it should be split at one pipe segment per line with the pipe on the
331
+ newline and a 2 space indent for the next section of the pipe. `\ ` should be
332
+ consistently used to indicate line continuation. This applies to a chain of
333
+ commands combined using `|` as well as to logical compounds using `||` and `&&`.
334
+
335
+ ```shell
336
+ # All fits on one line
337
+ command1 | command2
338
+
339
+ # Long commands
340
+ command1 \
341
+ | command2 \
342
+ | command3 \
343
+ | command4
344
+ ```
345
+
346
+ This helps readability when distinguishing a pipeline from a regular long
347
+ command continuation, particularly if the line is using both.
348
+
349
+ Comments will need to precede the whole pipeline. If the comment and pipeline
350
+ are large and complex, then it is worth considering moving low level details of
351
+ them aside by using a helper function.
352
+
353
+ <a id="s5.4-control-flow"></a>
354
+
355
+ <!-- section was previously titled "Loops" -->
356
+
357
+ <a id="s5.4-loops"></a>
358
+ <a id="loops"></a>
359
+
360
+ ### Control Flow
361
+
362
+ Put `; then` and `; do` on the same line as the `if`, `for`, or `while`.
363
+
364
+ Control flow statements in shell are a bit different, but we follow the same
365
+ principles as with braces when declaring functions. That is: `; then` and `; do`
366
+ should be on the same line as the `if`/`for`/`while`/`until`/`select`. `else`
367
+ should be on its own line and closing statements (`fi` and `done`) should be on
368
+ their own line vertically aligned with the opening statement.
369
+
370
+ Example:
371
+
372
+ ```shell
373
+ # If inside a function remember to declare the loop variable as
374
+ # a local to avoid it leaking into the global environment:
375
+ local dir
376
+ for dir in "${dirs_to_cleanup[@]}"; do
377
+ if [[ -d "${dir}/${SESSION_ID}" ]]; then
378
+ log_date "Cleaning up old files in ${dir}/${SESSION_ID}"
379
+ rm "${dir}/${SESSION_ID}/"* || error_message
380
+ else
381
+ mkdir -p "${dir}/${SESSION_ID}" || error_message
382
+ fi
383
+ done
384
+ ```
385
+
386
+ Although it is possible to
387
+ [omit `in "$@"`](https://www.gnu.org/software/bash/manual/html_node/Looping-Constructs.html#index-for)
388
+ in for loops we recommend consistently including it for clarity.
389
+
390
+ ```shell
391
+ for arg in "$@"; do
392
+ echo "argument: ${arg}"
393
+ done
394
+ ```
395
+
396
+ <a id="s5.5-case-statement"></a>
397
+
398
+ ### Case statement
399
+
400
+ * Indent alternatives by 2 spaces.
401
+ * A one-line alternative needs a space after the close parenthesis of the
402
+ pattern and before the `;;`.
403
+ * Long or multi-command alternatives should be split over multiple lines with
404
+ the pattern, actions, and `;;` on separate lines.
405
+
406
+ The matching expressions are indented one level from the `case` and `esac`.
407
+ Multiline actions are indented another level. In general, there is no need to
408
+ quote match expressions. Pattern expressions should not be preceded by an open
409
+ parenthesis. Avoid the `;&` and `;;&` notations.
410
+
411
+ ```shell
412
+ case "${expression}" in
413
+ a)
414
+ variable="…"
415
+ some_command "${variable}" "${other_expr}" …
416
+ ;;
417
+ absolute)
418
+ actions="relative"
419
+ another_command "${actions}" "${other_expr}" …
420
+ ;;
421
+ *)
422
+ error "Unexpected expression '${expression}'"
423
+ ;;
424
+ esac
425
+ ```
426
+
427
+ Simple commands may be put on the same line as the pattern <i>and</i>
428
+ `;;` as long as the expression remains readable. This is
429
+ often appropriate for single-letter option processing. When the
430
+ actions don't fit on a single line, put the pattern on a line on its
431
+ own, then the actions, then `;;` also on a line of its own.
432
+ When on the same line as the actions, use a space after the close
433
+ parenthesis of the pattern and another before the `;;`.
434
+
435
+ ```shell
436
+ verbose='false'
437
+ aflag=''
438
+ bflag=''
439
+ files=''
440
+ while getopts 'abf:v' flag; do
441
+ case "${flag}" in
442
+ a) aflag='true' ;;
443
+ b) bflag='true' ;;
444
+ f) files="${OPTARG}" ;;
445
+ v) verbose='true' ;;
446
+ *) error "Unexpected option ${flag}" ;;
447
+ esac
448
+ done
449
+ ```
450
+
451
+ <a id="s5.6-variable-expansion"></a>
452
+
453
+ ### Variable expansion
454
+
455
+ In order of precedence: Stay consistent with what you find; quote your
456
+ variables; prefer `"${var}"` over `"$var"`.
457
+
458
+ These are strongly recommended guidelines but not mandatory
459
+ regulation. Nonetheless, the fact that it's a recommendation and
460
+ not mandatory doesn't mean it should be taken lightly or downplayed.
461
+
462
+ They are listed in order of precedence.
463
+
464
+ * Stay consistent with what you find for existing code.
465
+ * Quote variables, see [Quoting section below](#quoting).
466
+ * Don't brace-delimit single character shell specials / positional parameters,
467
+ unless strictly necessary or avoiding deep confusion.
468
+
469
+ Prefer brace-delimiting all other variables.
470
+
471
+ ```shell
472
+ # Section of *recommended* cases.
473
+
474
+ # Preferred style for 'special' variables:
475
+ echo "Positional: $1" "$5" "$3"
476
+ echo "Specials: !=$!, -=$-, _=$_. ?=$?, #=$# *=$* @=$@ \$=$$ …"
477
+
478
+ # Braces necessary:
479
+ echo "many parameters: ${10}"
480
+
481
+ # Braces avoiding confusion:
482
+ # Output is "a0b0c0"
483
+ set -- a b c
484
+ echo "${1}0${2}0${3}0"
485
+
486
+ # Preferred style for other variables:
487
+ echo "PATH=${PATH}, PWD=${PWD}, mine=${some_var}"
488
+ while read -r f; do
489
+ echo "file=${f}"
490
+ done < <(find /tmp)
491
+ ```
492
+
493
+ ```shell
494
+ # Section of *discouraged* cases
495
+
496
+ # Unquoted vars, unbraced vars, brace-delimited single letter
497
+ # shell specials.
498
+ echo a=$avar "b=$bvar" "PID=${$}" "${1}"
499
+
500
+ # Confusing use: this is expanded as "${1}0${2}0${3}0",
501
+ # not "${10}${20}${30}
502
+ set -- a b c
503
+ echo "$10$20$30"
504
+ ```
505
+
506
+ NOTE: Using braces in `${var}` is *not* a form of quoting. "Double quotes" must
507
+ be used *as well*.
508
+
509
+ <a id="s5.7-quoting"></a>
510
+
511
+ ### Quoting
512
+
513
+ * Always quote strings containing variables, command substitutions, spaces or
514
+ shell meta characters, unless careful unquoted expansion is required or it's
515
+ a shell-internal integer (see next point).
516
+ * Use arrays for safe quoting of lists of elements, especially command-line
517
+ flags. See [Arrays](#arrays) below.
518
+ * Optionally quote shell-internal, readonly
519
+ [special variables](https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html)
520
+ that are defined to be integers: `$?`, `$#`, `$$`, `$!`. Prefer quoting of
521
+ "named" internal integer variables, e.g. PPID etc for consistency.
522
+ * Prefer quoting strings that are "words" (as opposed to command options or
523
+ path names).
524
+ * Be aware of the quoting rules for pattern matches in `[[ … ]]`. See the
525
+ [Test, `[ … ]`, and `[[ … ]]`](#tests) section below.
526
+ * Use `"$@"` unless you have a specific reason to use `$*`, such as simply
527
+ appending the arguments to a string in a message or log.
528
+
529
+ ```shell
530
+ # 'Single' quotes indicate that no substitution is desired.
531
+ # "Double" quotes indicate that substitution is required/tolerated.
532
+
533
+ # Simple examples
534
+
535
+ # "quote command substitutions"
536
+ # Note that quotes nested inside "$()" don't need escaping.
537
+ flag="$(some_command and its args "$@" 'quoted separately')"
538
+
539
+ # "quote variables"
540
+ echo "${flag}"
541
+
542
+ # Use arrays with quoted expansion for lists.
543
+ declare -a FLAGS
544
+ FLAGS=( --foo --bar='baz' )
545
+ readonly FLAGS
546
+ mybinary "${FLAGS[@]}"
547
+
548
+ # It's ok to not quote internal integer variables.
549
+ if (( $# > 3 )); then
550
+ echo "ppid=${PPID}"
551
+ fi
552
+
553
+ # "never quote literal integers"
554
+ value=32
555
+ # "quote command substitutions", even when you expect integers
556
+ number="$(generate_number)"
557
+
558
+ # "prefer quoting words", not compulsory
559
+ readonly USE_INTEGER='true'
560
+
561
+ # "quote shell meta characters"
562
+ echo 'Hello stranger, and well met. Earn lots of $$$'
563
+ echo "Process $$: Done making \$\$\$."
564
+
565
+ # "command options or path names"
566
+ # ($1 is assumed to contain a value here)
567
+ grep -li Hugo /dev/null "$1"
568
+
569
+ # Less simple examples
570
+ # "quote variables, unless proven false": ccs might be empty
571
+ git send-email --to "${reviewers}" ${ccs:+"--cc" "${ccs}"}
572
+
573
+ # Positional parameter precautions: $1 might be unset
574
+ # Single quotes leave regex as-is.
575
+ grep -cP '([Ss]pecial|\|?characters*)$' ${1:+"$1"}
576
+
577
+ # For passing on arguments,
578
+ # "$@" is right almost every time, and
579
+ # $* is wrong almost every time:
580
+ #
581
+ # * $* and $@ will split on spaces, clobbering up arguments
582
+ # that contain spaces and dropping empty strings;
583
+ # * "$@" will retain arguments as-is, so no args
584
+ # provided will result in no args being passed on;
585
+ # This is in most cases what you want to use for passing
586
+ # on arguments.
587
+ # * "$*" expands to one argument, with all args joined
588
+ # by (usually) spaces,
589
+ # so no args provided will result in one empty string
590
+ # being passed on.
591
+ #
592
+ # Consult
593
+ # https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html and
594
+ # https://mywiki.wooledge.org/BashGuide/Arrays for more
595
+
596
+ (set -- 1 "2 two" "3 three tres"; echo $#; set -- "$*"; echo "$#, $@")
597
+ (set -- 1 "2 two" "3 three tres"; echo $#; set -- "$@"; echo "$#, $@")
598
+ ```
599
+
600
+ <a id="s6-features-and-bugs"></a>
601
+
602
+ ## Features and Bugs
603
+
604
+ <a id="s6.1-shellcheck"></a>
605
+
606
+ ### ShellCheck
607
+
608
+ The [ShellCheck project](https://www.shellcheck.net/) identifies common bugs and
609
+ warnings for your shell scripts. It is recommended for all scripts, large or
610
+ small.
611
+
612
+ <a id="s6.2-command-substitution"></a>
613
+
614
+ ### Command Substitution
615
+
616
+ Use `$(command)` instead of backticks.
617
+
618
+ Nested backticks require escaping the inner ones with `\ `.
619
+ The `$(command)` format doesn't change when nested and is
620
+ easier to read.
621
+
622
+ Example:
623
+
624
+ ```shell
625
+ # This is preferred:
626
+ var="$(command "$(command1)")"
627
+ ```
628
+
629
+ ```shell
630
+ # This is not:
631
+ var="`command \`command1\``"
632
+ ```
633
+
634
+ <a id="s6.3-tests"></a>
635
+
636
+ <a id="tests"></a>
637
+ ### Test, `[ … ]`, and `[[ … ]]`
638
+
639
+ `[[ … ]]` is preferred over `[ … ]`, `test` and `/usr/bin/[`.
640
+
641
+ `[[ … ]]` reduces errors as no pathname expansion or word splitting takes place
642
+ between `[[` and `]]`. In addition, `[[ … ]]` allows for pattern and regular
643
+ expression matching, while `[ … ]` does not.
644
+
645
+ ```shell
646
+ # This ensures the string on the left is made up of characters in
647
+ # the alnum character class followed by the string name.
648
+ # Note that the RHS should not be quoted here.
649
+ if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
650
+ echo "Match"
651
+ fi
652
+
653
+ # This matches the exact pattern "f*" (Does not match in this case)
654
+ if [[ "filename" == "f*" ]]; then
655
+ echo "Match"
656
+ fi
657
+ ```
658
+
659
+ ```shell
660
+ # This gives a "too many arguments" error as f* is expanded to the
661
+ # contents of the current directory. It might also trigger the
662
+ # "unexpected operator" error because `[` does not support `==`, only `=`.
663
+ if [ "filename" == f* ]; then
664
+ echo "Match"
665
+ fi
666
+ ```
667
+
668
+ For the gory details, see E14 in the [Bash FAQ](http://tiswww.case.edu/php/chet/bash/FAQ)
669
+
670
+ <a id="s6.4-testing-strings"></a>
671
+
672
+ ### Testing Strings
673
+
674
+ Use quotes rather than filler characters where possible.
675
+
676
+ Bash is smart enough to deal with an empty string in a test. So, given
677
+ that the code is much easier to read, use tests for empty/non-empty
678
+ strings or empty strings rather than filler characters.
679
+
680
+ ```shell
681
+ # Do this:
682
+ if [[ "${my_var}" == "some_string" ]]; then
683
+ do_something
684
+ fi
685
+
686
+ # -z (string length is zero) and -n (string length is not zero) are
687
+ # preferred over testing for an empty string
688
+ if [[ -z "${my_var}" ]]; then
689
+ do_something
690
+ fi
691
+
692
+ # This is OK (ensure quotes on the empty side), but not preferred:
693
+ if [[ "${my_var}" == "" ]]; then
694
+ do_something
695
+ fi
696
+ ```
697
+
698
+ ```shell
699
+ # Not this:
700
+ if [[ "${my_var}X" == "some_stringX" ]]; then
701
+ do_something
702
+ fi
703
+ ```
704
+
705
+ To avoid confusion about what you're testing for, explicitly use
706
+ `-z` or `-n`.
707
+
708
+ ```shell
709
+ # Use this
710
+ if [[ -n "${my_var}" ]]; then
711
+ do_something
712
+ fi
713
+ ```
714
+
715
+ ```shell
716
+ # Instead of this
717
+ if [[ "${my_var}" ]]; then
718
+ do_something
719
+ fi
720
+ ```
721
+
722
+ For clarity, use `==` for equality rather than
723
+ `=` even though both work. The former encourages the use of
724
+ `[[` and the latter can be confused with an assignment.
725
+ However, be careful when using `<` and `>`
726
+ in `[[ … ]]` which performs a lexicographical comparison.
727
+ Use `(( … ))` or `-lt` and `-gt` for
728
+ numerical comparison.
729
+
730
+ ```shell
731
+ # Use this
732
+ if [[ "${my_var}" == "val" ]]; then
733
+ do_something
734
+ fi
735
+
736
+ if (( my_var > 3 )); then
737
+ do_something
738
+ fi
739
+
740
+ if [[ "${my_var}" -gt 3 ]]; then
741
+ do_something
742
+ fi
743
+ ```
744
+
745
+ ```shell
746
+ # Instead of this
747
+ if [[ "${my_var}" = "val" ]]; then
748
+ do_something
749
+ fi
750
+
751
+ # Probably unintended lexicographical comparison.
752
+ if [[ "${my_var}" > 3 ]]; then
753
+ # True for 4, false for 22.
754
+ do_something
755
+ fi
756
+ ```
757
+
758
+ <a id="s6.5-wildcard-expansion-of-filenames"></a>
759
+
760
+ ### Wildcard Expansion of Filenames
761
+
762
+ Use an explicit path when doing wildcard expansion of filenames.
763
+
764
+ As filenames can begin with a `-`, it's a lot safer to
765
+ expand wildcards with `./*` instead of `*`.
766
+
767
+ ```shell
768
+ # Here's the contents of the directory:
769
+ # -f -r somedir somefile
770
+
771
+ # Incorrectly deletes almost everything in the directory by force
772
+ psa@bilby$ rm -v *
773
+ removed directory: `somedir'
774
+ removed `somefile'
775
+ ```
776
+
777
+ ```shell
778
+ # As opposed to:
779
+ psa@bilby$ rm -v ./*
780
+ removed `./-f'
781
+ removed `./-r'
782
+ rm: cannot remove `./somedir': Is a directory
783
+ removed `./somefile'
784
+ ```
785
+
786
+ <a id="s6.6-eval"></a>
787
+
788
+ ### Eval
789
+
790
+ `eval` should be avoided.
791
+
792
+
793
+ Eval munges the input when used for assignment to variables and can
794
+ set variables without making it possible to check what those variables
795
+ were.
796
+
797
+ ```shell
798
+ # What does this set?
799
+ # Did it succeed? In part or whole?
800
+ eval $(set_my_variables)
801
+
802
+ # What happens if one of the returned values has a space in it?
803
+ variable="$(eval some_function)"
804
+ ```
805
+
806
+ <a id="s6.7-arrays"></a>
807
+
808
+ ### Arrays
809
+
810
+ Bash arrays should be used to store lists of elements, to avoid quoting
811
+ complications. This particularly applies to argument lists. Arrays
812
+ should not be used to facilitate more complex data structures (see
813
+ [When to use Shell](#when-to-use-shell) above).
814
+
815
+ Arrays store an ordered collection of strings, and can be safely
816
+ expanded into individual elements for a command or loop.
817
+
818
+ Using a single string for multiple command arguments should be
819
+ avoided, as it inevitably leads to authors using `eval`
820
+ or trying to nest quotes inside the string, which does not give
821
+ reliable or readable results and leads to needless complexity.
822
+
823
+ ```shell
824
+ # An array is assigned using parentheses, and can be appended to
825
+ # with +=( … ).
826
+ declare -a flags
827
+ flags=(--foo --bar='baz')
828
+ flags+=(--greeting="Hello ${name}")
829
+ mybinary "${flags[@]}"
830
+ ```
831
+
832
+ ```shell
833
+ # Don’t use strings for sequences.
834
+ flags='--foo --bar=baz'
835
+ flags+=' --greeting="Hello world"' # This won’t work as intended.
836
+ mybinary ${flags}
837
+ ```
838
+
839
+ ```shell
840
+ # Command expansions return single strings, not arrays. Avoid
841
+ # unquoted expansion in array assignments because it won’t
842
+ # work correctly if the command output contains special
843
+ # characters or whitespace.
844
+
845
+ # This expands the listing output into a string, then does special keyword
846
+ # expansion, and then whitespace splitting. Only then is it turned into a
847
+ # list of words. The ls command may also change behavior based on the user's
848
+ # active environment!
849
+ declare -a files=($(ls /directory))
850
+
851
+ # The get_arguments writes everything to STDOUT, but then goes through the
852
+ # same expansion process above before turning into a list of arguments.
853
+ mybinary $(get_arguments)
854
+ ```
855
+
856
+ <a id="s6.7.1-arrays-pros"></a>
857
+
858
+ #### Arrays Pros
859
+
860
+ * Using Arrays allows lists of things without confusing quoting semantics.
861
+ Conversely, not using arrays leads to misguided attempts to nest quoting
862
+ inside a string.
863
+ * Arrays make it possible to safely store sequences/lists of arbitrary
864
+ strings, including strings containing whitespace.
865
+
866
+ <a id="s6.7.2-arrays-cons"></a>
867
+
868
+ #### Arrays Cons
869
+
870
+ Using arrays can risk a script’s complexity growing.
871
+
872
+ <a id="s6.7.3-arrays-decision"></a>
873
+
874
+ #### Arrays Decision
875
+
876
+ Arrays should be used to safely create and pass around lists. In
877
+ particular, when building a set of command arguments, use arrays to
878
+ avoid confusing quoting issues. Use quoted expansion –
879
+ `"${array[@]}"` – to access arrays. However, if more
880
+ advanced data manipulation is required, shell scripting should be
881
+ avoided altogether; see [above](#when-to-use-shell).
882
+
883
+ <a id="s6.8-pipes-to-while"></a>
884
+
885
+ ### Pipes to While
886
+
887
+ Use process substitution or the `readarray` builtin (bash4+) in preference to
888
+ piping to `while`. Pipes create a subshell, so any variables modified within a
889
+ pipeline do not propagate to the parent shell.
890
+
891
+ The implicit subshell in a pipe to `while` can introduce subtle bugs that are
892
+ hard to track down.
893
+
894
+ ```shell
895
+ last_line='NULL'
896
+ your_command | while read -r line; do
897
+ if [[ -n "${line}" ]]; then
898
+ last_line="${line}"
899
+ fi
900
+ done
901
+
902
+ # This will always output 'NULL'!
903
+ echo "${last_line}"
904
+ ```
905
+
906
+ Using process substitution also creates a subshell. However, it allows
907
+ redirecting from a subshell to a `while` without putting the `while` (or any
908
+ other command) in a subshell.
909
+
910
+ ```shell
911
+ last_line='NULL'
912
+ while read line; do
913
+ if [[ -n "${line}" ]]; then
914
+ last_line="${line}"
915
+ fi
916
+ done < <(your_command)
917
+
918
+ # This will output the last non-empty line from your_command
919
+ echo "${last_line}"
920
+ ```
921
+
922
+ Alternatively, use the `readarray` builtin to read the file into an array, then
923
+ loop over the array's contents. Notice that (for the same reason as above) you
924
+ need to use a process substitution with `readarray` rather than a pipe, but with
925
+ the advantage that the input generation for the loop is located before it,
926
+ rather than after.
927
+
928
+ ```shell
929
+ last_line='NULL'
930
+ readarray -t lines < <(your_command)
931
+ for line in "${lines[@]}"; do
932
+ if [[ -n "${line}" ]]; then
933
+ last_line="${line}"
934
+ fi
935
+ done
936
+ echo "${last_line}"
937
+ ```
938
+
939
+ > Note: Be cautious using a for-loop to iterate over output, as in `for var in
940
+ > $(...)`, as the output is split by whitespace, not by line. Sometimes you will
941
+ > know this is safe because the output can't contain any unexpected whitespace,
942
+ > but where this isn't obvious or doesn't improve readability (such as a long
943
+ > command inside `$(...)`), a `while read` loop or `readarray` is often safer
944
+ > and clearer.
945
+
946
+ <a id="s6.9-arithmetic"></a>
947
+
948
+ ### Arithmetic
949
+
950
+ Always use `(( … ))` or `$(( … ))` rather than
951
+ `let` or `$[ … ]` or `expr`.
952
+
953
+ Never use the `$[ … ]` syntax, the `expr`
954
+ command, or the `let` built-in.
955
+
956
+ `<` and `>` don't perform numerical
957
+ comparison inside `[[ … ]]` expressions (they perform
958
+ lexicographical comparisons instead; see [Testing Strings](#testing-strings)).
959
+ For preference, don't use `[[ … ]]` *at all* for numeric comparisons, use
960
+ `(( … ))` instead.
961
+
962
+ It is recommended to avoid using `(( … ))` as a standalone
963
+ statement, and otherwise be wary of its expression evaluating to zero
964
+ - particularly with `set -e` enabled. For example,
965
+ `set -e; i=0; (( i++ ))` will cause the shell to exit.
966
+
967
+ ```shell
968
+ # Simple calculation used as text - note the use of $(( … )) within
969
+ # a string.
970
+ echo "$(( 2 + 2 )) is 4"
971
+
972
+ # When performing arithmetic comparisons for testing
973
+ if (( a < b )); then
974
+
975
+ fi
976
+
977
+ # Some calculation assigned to a variable.
978
+ (( i = 10 * j + 400 ))
979
+ ```
980
+
981
+ ```shell
982
+ # This form is non-portable and deprecated
983
+ i=$[2 * 10]
984
+
985
+ # Despite appearances, 'let' isn't one of the declarative keywords,
986
+ # so unquoted assignments are subject to globbing wordsplitting.
987
+ # For the sake of simplicity, avoid 'let' and use (( … ))
988
+ let i="2 + 2"
989
+
990
+ # The expr utility is an external program and not a shell builtin.
991
+ i=$( expr 4 + 4 )
992
+
993
+ # Quoting can be error prone when using expr too.
994
+ i=$( expr 4 '*' 4 )
995
+ ```
996
+
997
+ Stylistic considerations aside, the shell's built-in arithmetic is
998
+ many times faster than `expr`.
999
+
1000
+ When using variables, the `${var}` (and `$var`)
1001
+ forms are not required within `$(( … ))`. The shell knows
1002
+ to look up `var` for you, and omitting the
1003
+ `${…}` leads to cleaner code. This is slightly contrary to
1004
+ the previous rule about always using braces, so this is a
1005
+ recommendation only.
1006
+
1007
+ ```shell
1008
+ # N.B.: Remember to declare your variables as integers when
1009
+ # possible, and to prefer local variables over globals.
1010
+ local -i hundred="$(( 10 * 10 ))"
1011
+ declare -i five="$(( 10 / 2 ))"
1012
+
1013
+ # Increment the variable "i" by three.
1014
+ # Note that:
1015
+ # - We do not write ${i} or $i.
1016
+ # - We put a space after the (( and before the )).
1017
+ (( i += 3 ))
1018
+
1019
+ # To decrement the variable "i" by five:
1020
+ (( i -= 5 ))
1021
+
1022
+ # Do some complicated computations.
1023
+ # Note that normal arithmetic operator precedence is observed.
1024
+ hr=2
1025
+ min=5
1026
+ sec=30
1027
+ echo "$(( hr * 3600 + min * 60 + sec ))" # prints 7530 as expected
1028
+ ```
1029
+
1030
+ <a id="s6.10-aliases"></a>
1031
+
1032
+ ## Aliases
1033
+
1034
+ Although commonly seen in `.bashrc` files, aliases should be avoided in scripts.
1035
+ As the
1036
+ [Bash manual](https://www.gnu.org/software/bash/manual/html_node/Aliases.html)
1037
+ notes:
1038
+
1039
+ > For almost every purpose, shell functions are preferred over aliases.
1040
+
1041
+ Aliases are cumbersome to work with because they require carefully quoting and
1042
+ escaping their contents, and mistakes can be hard to notice.
1043
+
1044
+ ```shell
1045
+ # this evaluates $RANDOM once when the alias is defined,
1046
+ # so the echo'ed string will be the same on each invocation
1047
+ alias random_name="echo some_prefix_${RANDOM}"
1048
+ ```
1049
+
1050
+ Functions provide a superset of alias' functionality and should always be
1051
+ preferred. .
1052
+
1053
+ ```shell
1054
+ random_name() {
1055
+ echo "some_prefix_${RANDOM}"
1056
+ }
1057
+
1058
+ # Note that unlike aliases function's arguments are accessed via $@
1059
+ fancy_ls() {
1060
+ ls -lh "$@"
1061
+ }
1062
+ ```
1063
+
1064
+ <a id="s7-naming-conventions"></a>
1065
+
1066
+ ## Naming Conventions
1067
+
1068
+ <a id="s7.1-function-names"></a>
1069
+
1070
+ ### Function Names
1071
+
1072
+ Lower-case, with underscores to separate words. Separate libraries with `::`.
1073
+ Parentheses are required after the function name. The keyword `function` is
1074
+ optional, but must be used consistently throughout a project.
1075
+
1076
+ If you're writing single functions, use lowercase and separate words with
1077
+ underscore. If you're writing a package, separate package names with `::`.
1078
+ However, functions intended for interactive use may choose to avoid colons as it
1079
+ can confuse bash auto-completion.
1080
+
1081
+ Braces must be on the same line as the function name (as with other languages at
1082
+ Google) and no space between the function name and the parenthesis.
1083
+
1084
+ ```shell
1085
+ # Single function
1086
+ my_func() {
1087
+
1088
+ }
1089
+
1090
+ # Part of a package
1091
+ mypackage::my_func() {
1092
+
1093
+ }
1094
+ ```
1095
+
1096
+ The `function` keyword is extraneous when "()" is present
1097
+ after the function name, but enhances quick identification of
1098
+ functions.
1099
+
1100
+ <a id="s7.2-variable-names"></a>
1101
+
1102
+ ### Variable Names
1103
+
1104
+ Same as for function names.
1105
+
1106
+ Variables names for loops should be similarly named for any variable
1107
+ you're looping through.
1108
+
1109
+ ```shell
1110
+ for zone in "${zones[@]}"; do
1111
+ something_with "${zone}"
1112
+ done
1113
+ ```
1114
+
1115
+ <a id="s7.3-constants-and-environment-variable-names"></a>
1116
+ <a id="s7.5-read-only-variables"></a>
1117
+
1118
+ ### Constants, Environment Variables, and readonly Variables
1119
+
1120
+ Constants and anything exported to the environment should be capitalized,
1121
+ separated with underscores, and declared at the top of the file.
1122
+
1123
+ ```shell
1124
+ # Constant
1125
+ readonly PATH_TO_FILES='/some/path'
1126
+
1127
+ # Both constant and exported to the environment
1128
+ declare -xr ORACLE_SID='PROD'
1129
+ ```
1130
+
1131
+ For the sake of clarity `readonly` or `export` is recommended vs. the equivalent
1132
+ `declare` commands. You can do one after the other, like:
1133
+
1134
+ ```shell
1135
+ # Constant
1136
+ readonly PATH_TO_FILES='/some/path'
1137
+ export PATH_TO_FILES
1138
+ ```
1139
+
1140
+ It's OK to set a constant at runtime or in a conditional, but it should be made
1141
+ readonly immediately afterwards.
1142
+
1143
+ ```shell
1144
+ ZIP_VERSION="$(dpkg --status zip | sed -n 's/^Version: //p')"
1145
+ if [[ -z "${ZIP_VERSION}" ]]; then
1146
+ ZIP_VERSION="$(pacman -Q --info zip | sed -n 's/^Version *: //p')"
1147
+ fi
1148
+ if [[ -z "${ZIP_VERSION}" ]]; then
1149
+ handle_error_and_quit
1150
+ fi
1151
+ readonly ZIP_VERSION
1152
+ ```
1153
+
1154
+ <a id="s7.4-source-filenames"></a>
1155
+
1156
+ ### Source Filenames
1157
+
1158
+ Lowercase, with underscores to separate words if desired.
1159
+
1160
+ This is for consistency with other code styles in Google:
1161
+ `maketemplate` or `make_template` but not
1162
+ `make-template`.
1163
+
1164
+ <a id="s7.5-use-local-variables"></a>
1165
+ <a id="s7.6-use-local-variables"></a>
1166
+
1167
+ ### Use Local Variables
1168
+
1169
+ Declare function-specific variables with `local`.
1170
+
1171
+ Ensure that local variables are only seen inside a function and its children by
1172
+ using `local` when declaring them. This avoids polluting the global namespace
1173
+ and inadvertently setting variables that may have significance outside the
1174
+ function.
1175
+
1176
+ Declaration and assignment must be separate statements when the
1177
+ assignment value is provided by a command substitution; as the
1178
+ `local` builtin does not propagate the exit code from the
1179
+ command substitution.
1180
+
1181
+ ```shell
1182
+ my_func2() {
1183
+ local name="$1"
1184
+
1185
+ # Separate lines for declaration and assignment:
1186
+ local my_var
1187
+ my_var="$(my_func)"
1188
+ (( $? == 0 )) || return
1189
+
1190
+
1191
+ }
1192
+ ```
1193
+
1194
+ ```shell
1195
+ my_func2() {
1196
+ # DO NOT do this:
1197
+ # $? will always be zero, as it contains the exit code of 'local', not my_func
1198
+ local my_var="$(my_func)"
1199
+ (( $? == 0 )) || return
1200
+
1201
+
1202
+ }
1203
+ ```
1204
+
1205
+ <a id="s7.6-function-location"></a>
1206
+ <a id="s7.7-function-location"></a>
1207
+
1208
+ ### Function Location
1209
+
1210
+ Put all functions together in the file just below constants. Don't hide
1211
+ executable code between functions. Doing so makes the code difficult to follow
1212
+ and results in nasty surprises when debugging.
1213
+
1214
+ If you've got functions, put them all together near the top of the
1215
+ file. Only includes, `set` statements and setting constants
1216
+ may be done before declaring functions.
1217
+
1218
+ <a id="s7.7-main"></a>
1219
+ <a id="s7.8-main"></a>
1220
+
1221
+ ### main
1222
+
1223
+ A function called `main` is required for scripts long enough
1224
+ to contain at least one other function.
1225
+
1226
+ In order to easily find the start of the program, put the main program in a
1227
+ function called `main` as the bottom-most function. This provides consistency
1228
+ with the rest of the code base as well as allowing you to define more variables
1229
+ as `local` (which can't be done if the main code is not a function). The last
1230
+ non-comment line in the file should be a call to `main`:
1231
+
1232
+ ```shell
1233
+ main "$@"
1234
+ ```
1235
+
1236
+ Obviously, for short scripts where it's just a linear flow,
1237
+ `main` is overkill and so is not required.
1238
+
1239
+ <a id="s8-calling-commands"></a>
1240
+
1241
+ ## Calling Commands
1242
+
1243
+ <a id="s8.1-checking-return-values"></a>
1244
+
1245
+ ### Checking Return Values
1246
+
1247
+ Always check return values and give informative return values.
1248
+
1249
+ For unpiped commands, use `$?` or check directly via an
1250
+ `if` statement to keep it simple.
1251
+
1252
+ Example:
1253
+
1254
+ ```shell
1255
+ if ! mv "${file_list[@]}" "${dest_dir}/"; then
1256
+ echo "Unable to move ${file_list[*]} to ${dest_dir}" >&2
1257
+ exit 1
1258
+ fi
1259
+
1260
+ # Or
1261
+ mv "${file_list[@]}" "${dest_dir}/"
1262
+ if (( $? != 0 )); then
1263
+ echo "Unable to move ${file_list[*]} to ${dest_dir}" >&2
1264
+ exit 1
1265
+ fi
1266
+ ```
1267
+
1268
+ Bash also has the `PIPESTATUS` variable that allows
1269
+ checking of the return code from all parts of a pipe. If it's only
1270
+ necessary to check success or failure of the whole pipe, then the
1271
+ following is acceptable:
1272
+
1273
+ ```shell
1274
+ tar -cf - ./* | ( cd "${dir}" && tar -xf - )
1275
+ if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then
1276
+ echo "Unable to tar files to ${dir}" >&2
1277
+ fi
1278
+ ```
1279
+
1280
+ However, as `PIPESTATUS` will be overwritten as soon as you
1281
+ do any other command, if you need to act differently on errors based
1282
+ on where it happened in the pipe, you'll need to assign
1283
+ `PIPESTATUS` to another variable immediately after running
1284
+ the command (don't forget that `[` is a command and will
1285
+ wipe out `PIPESTATUS`).
1286
+
1287
+ ```shell
1288
+ tar -cf - ./* | ( cd "${DIR}" && tar -xf - )
1289
+ return_codes=( "${PIPESTATUS[@]}" )
1290
+ if (( return_codes[0] != 0 )); then
1291
+ do_something
1292
+ fi
1293
+ if (( return_codes[1] != 0 )); then
1294
+ do_something_else
1295
+ fi
1296
+ ```
1297
+
1298
+ <a id="s8.2-builtin-commands-vs-external-commands"></a>
1299
+
1300
+ ### Builtin Commands vs. External Commands
1301
+
1302
+ Given the choice between invoking a shell builtin and invoking a
1303
+ separate process, choose the builtin.
1304
+
1305
+ We prefer the use of builtins such as the
1306
+ [*Parameter Expansion*](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html)
1307
+ functionality provided by `bash` as it's more efficient, robust, and portable
1308
+ (especially when compared to things like `sed`). See also the
1309
+ [`=~` operator](https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html#index-_005b_005b).
1310
+
1311
+ Examples:
1312
+
1313
+ ```shell
1314
+ # Prefer this:
1315
+ addition="$(( X + Y ))"
1316
+ substitution="${string/#foo/bar}"
1317
+ if [[ "${string}" =~ foo:(\d+) ]]; then
1318
+ extraction="${BASH_REMATCH[1]}"
1319
+ fi
1320
+ ```
1321
+
1322
+ ```shell
1323
+ # Instead of this:
1324
+ addition="$(expr "${X}" + "${Y}")"
1325
+ substitution="$(echo "${string}" | sed -e 's/^foo/bar/')"
1326
+ extraction="$(echo "${string}" | sed -e 's/foo:\([0-9]\)/\1/')"
1327
+ ```
1328
+
1329
+ <a id="s9-conclusion"></a>
1330
+
1331
+ ## When in Doubt: Be Consistent
1332
+
1333
+ Using one style consistently through our codebase lets us focus on other (more
1334
+ important) issues. Consistency also allows for automation. In many cases, rules
1335
+ that are attributed to “Be Consistent” boil down to “Just pick one and stop
1336
+ worrying about it”; the potential value of allowing flexibility on these points
1337
+ is outweighed by the cost of having people argue over them.
1338
+
1339
+ However, there are limits to consistency. It is a good tie breaker when there is
1340
+ no clear technical argument, nor a long-term direction. Consistency should not
1341
+ generally be used as a justification to do things in an old style without
1342
+ considering the benefits of the new style, or the tendency of the codebase to
1343
+ converge on newer styles over time.