summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-02-22 11:23:54 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-02-22 11:23:54 +0200
commit55ff42d0144cb303d8a1b5c02e630c72e19ec517 (patch)
tree17dec1d12c32f58c273cf52df69096254cb9e4f9
parent79a23985860126f59cf0c26f9d8ee98001c9f95c (diff)
Update bash guide to always use [[ ]]
-rw-r--r--doc/bash-style.cli49
1 files changed, 34 insertions, 15 deletions
diff --git a/doc/bash-style.cli b/doc/bash-style.cli
index 8de01da..3f620f4 100644
--- a/doc/bash-style.cli
+++ b/doc/bash-style.cli
@@ -48,7 +48,7 @@ For \c{if}/\c{while} and \c{for}/\c{do} the corresponding \c{then} or \c{do}
is written on the same line after a semicolon, for example:
\
-if [ ... ]; then
+if [[ ... ]]; then
...
fi
@@ -60,9 +60,8 @@ done
Do use \c{elif} instead of nested \c{else} and \c{if} (and consider if
\c{case} can be used instead).
-For \c{if} use \c{[ ]} for basic tests and \c{[[ ]]} if the previous form is
-not sufficient or hairy. In particular, \c{[[ ]]} results in cleaner code
-for complex expressions, for example:
+For \c{if}/\c{while} use \c{[[ ]]} since it results in cleaner code for
+complex expressions, for example:
\
if [[ \"$foo\" && (\"$bar\" || \"$baz\") ]]; then
@@ -70,6 +69,9 @@ if [[ \"$foo\" && (\"$bar\" || \"$baz\") ]]; then
fi
\
+\N|If for some reason you need the semantics of \c{[}, use \c{test} instead to
+make it clear this is intentional.|
+
\h1#struct|Structure|
The overall structure of the script should be as follows:
@@ -148,7 +150,7 @@ file=
Parse the command line options/arguments. For example:
\
-while [ \"$#\" -gt 0 ]; do
+while [[ \"$#\" -gt 0 ]]; do
case \"$1\" in
-q)
quiet=\"y\"
@@ -160,7 +162,7 @@ while [ \"$#\" -gt 0 ]; do
shift
;;
*)
- if [ -n \"$file\" ]; then
+ if [[ -n \"$file\" ]]; then
error \"$usage\"
fi
@@ -179,11 +181,11 @@ then always strip the trailing slash (as shown above for the \c{-t} option).
Validate option/argument values. For example:
\
-if [ -z \"$file\" ]; then
+if [[ -z \"$file\" ]]; then
error \"$usage\"
fi
-if [ ! -d \"$file\" ]; then
+if [[ ! -d \"$file\" ]]; then
error \"'$file' does not exist or is not a directory\"
fi
\
@@ -199,11 +201,14 @@ functions, then define them just before use.
We quote every variable expansion, no exceptions. For example:
\
-if [ -n \"$foo\" ]; then
+if [[ -n \"$foo\" ]]; then
...
fi
\
+\N|While there is no word splitting in the \c{[[ ]]} context, we still quote
+variable expansions for consistency.|
+
This also applies to command substitution (which we always write as
\c{$(foo arg)} rather than \c{`foo arg`}), for example:
@@ -232,13 +237,27 @@ option=--quiet # Option name.
seds='s%^./%%' # sed script.
\
-Take care to quote globs that are not meant to be expanded. And since quoting
-will inhibit globbing, you may end up with expansions along these lines:
+Take care to quote globs that are not meant to be expanded, for example:
+
+\
+unset \"array[0]\"
+\
+
+And since quoting will inhibit globbing, you may end up with expansions along
+these lines:
\
rm -f \"$dir/$name\".*
\
+Note also that globbing is not performed in the \c{[[ ]]} context so this is
+ok:
+
+if [[ -v array[0] ]]; then
+ ...
+fi
+
+
\N|One exception to this quoting rule is arithmetic expansion (\c{$((\ ))}):
Bash treats it as if it was double-quoted and, as a result, any inner quoting
is treated literally. For example:
@@ -259,7 +278,7 @@ typical example of a space-aware argument handling:
\
files=()
-while [ \"$#\" -gt 0 ]; do
+while [[ \"$#\" -gt 0 ]]; do
case \"$1\" in
...
@@ -304,11 +323,11 @@ can have terse and natural looking conditions, for example:
first=true
while ...; do
- if [ ! \"$first\" ]; then
+ if [[ ! \"$first\" ]]; then
...
fi
- if [ \"$first\" ]; then
+ if [[ \"$first\" ]]; then
first=
fi
@@ -601,7 +620,7 @@ cleanup /no/such/dir | cat
r=\"${PIPESTATUS[0]}\"
set -o pipefail
-if [ \"$r\" -ne 0 ]; then
+if [[ \"$r\" -ne 0 ]]; then
...
fi
\