From 55ff42d0144cb303d8a1b5c02e630c72e19ec517 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 22 Feb 2021 11:23:54 +0200 Subject: Update bash guide to always use [[ ]] --- doc/bash-style.cli | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file 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 \ -- cgit v1.1