Table of Contents for
Bash Quick Start Guide

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Bash Quick Start Guide by Tom Ryder Published by Packt Publishing, 2018
  1. Bash Quick Start Guide
  2. Title Page
  3. Copyright and Credits
  4. Bash Quick Start Guide
  5. Dedication
  6. Packt Upsell
  7. Why subscribe?
  8. Packt.com
  9. Contributors
  10. About the author
  11. About the reviewers
  12. Packt is searching for authors like you
  13. Table of Contents
  14. Preface
  15. Who this book is for
  16. What this book covers
  17. To get the most out of this book
  18. Download the example code files
  19. Download the color images
  20. Conventions used
  21. Get in touch
  22. Reviews
  23. What is Bash?
  24. What Bash is and is not
  25. Getting Bash
  26. Checking Bash is running
  27. Switching the login shell to Bash
  28. Identifying the Bash version number
  29. Upgrading Bash on macOS X
  30. Understanding Bash features
  31. POSIX shell script features
  32. Bash-specific features
  33. Do I need Bash?
  34. Choosing when to apply Bash
  35. Choosing when to avoid Bash
  36. Getting help with Bash
  37. Summary
  38. Bash Command Structure
  39. Using Bash interactively
  40. Interactive key bindings
  41. Simple commands
  42. Shell metacharacters
  43. Quoting
  44. Escaping
  45. Single quotes
  46. Double quotes
  47. Quote concatenation
  48. Running commands in sequence
  49. Exit values
  50. Stopping a command list on error
  51. Running a command in the background
  52. Summary
  53. Essential Commands
  54. Distinguishing command types
  55. Essential Bash builtin commands
  56. The type command
  57. The echo command
  58. The printf command
  59. The pwd command
  60. Tilde paths
  61. The cd command
  62. Changing the directory in scripts
  63. The set command
  64. The declare command
  65. The test, [, and [[ commands
  66. Essential system commands
  67. The ls command
  68. Getting filename lists without ls
  69. The mv command
  70. The cp command
  71. The rm and rmdir commands
  72. The grep command
  73. The cut command
  74. The wc command
  75. Getting file sizes with wc or du
  76. The find command
  77. Executing commands for each result
  78. A note about find and xargs
  79. The sort and uniq commands
  80. Summary
  81. Input, Output, and Redirection
  82. Redirecting output
  83. Redirection paths
  84. Avoiding overwrites
  85. Appending to files
  86. Understanding created file permissions
  87. Choosing permissions for created files
  88. Redirecting errors
  89. Combining errors with output
  90. Blocking errors completely
  91. Sending output to more than one place
  92. Redirecting input
  93. Using a long string as input with here-documents
  94. Using pipes
  95. Adding file contents to a stream
  96. Piping output from multiple programs
  97. Filtering programs
  98. The sed stream editor
  99. The AWK programming language
  100. Summary
  101. Variables and Patterns
  102. Using variables
  103. Listing variables
  104. Naming variables
  105. Variable name case
  106. Clearing variables
  107. Environment variables
  108. Calling programs with environment variables
  109. Expanding variables
  110. Reading a value into a variable
  111. Getting command output in variables
  112. Parameter expansion forms
  113. Specifying default values
  114. String chopping
  115. Extracting substrings
  116. Getting string length
  117. Substituting strings
  118. Changing case
  119. Combining parameter expansion forms
  120. Doing math in Bash
  121. Fixed or floating-point arithmetic
  122. Using globs
  123. Configuring globbing behavior
  124. Including dot files, but excluding dot and dot-dot
  125. Expanding to nothing
  126. Case-insensitive globbing
  127. Extended globbing
  128. Using arrays
  129. Glob expansion in arrays
  130. Associative arrays
  131. Summary
  132. Loops and Conditionals
  133. Using the if keyword
  134. Using the test command
  135. Using the [ command
  136. Using the [[ keyword
  137. Arithmetic conditions
  138. Switching with the case keyword
  139. Looping over shell words with for
  140. Skipping an iteration
  141. Ending the loop
  142. Misuse of for loops
  143. Using Bash's C-style for loops
  144. Using while loops
  145. Infinite loops
  146. Reading data line by line
  147. Field splitting
  148. Saving fields into arrays
  149. Choosing the splitting character
  150. Disabling whitespace trimming
  151. Reading process output
  152. Avoiding subshell problems
  153. Avoiding input problems with ssh
  154. Summary
  155. Scripts, Functions, and Aliases
  156. Aliases
  157. Defining new aliases
  158. Understanding shortcomings with aliases
  159. Functions
  160. Defining functions
  161. Passing arguments to functions
  162. Using --  to separate options from filenames
  163. Getting all the arguments
  164. Returning values from functions
  165. Understanding function input and output
  166. Function scope
  167. Reloading functions at shell startup
  168. Scripts
  169. Scripting methods
  170. Writing a shebang script
  171. Finding scripts with $PATH
  172. System bindir
  173. User bindir
  174. Arguments to scripts
  175. Understanding sh vs bash
  176. Using env
  177. Choosing between functions and scripts
  178. Using functions in scripts
  179. Summary
  180. Best Practices
  181. Quoting correctly
  182. When you don't want quotes
  183. Handling filenames starting with dashes
  184. Separating output and diagnostics
  185. Keeping scripts brief and simple
  186. Keeping scripts flexible
  187. Respecting and applying the user's configuration
  188. Allowing scripts to run without user input
  189. Limiting the scope of shell state changes
  190. Avoiding path anti-patterns
  191. Avoiding Bash for untrusted user input
  192. Documenting scripts
  193. Writing comments
  194. Providing help output
  195. Writing manual pages
  196. Using temporary files cleanly
  197. Cleaning up after a script
  198. Tools to check shell scripts for problems
  199. Summary
  200. Other Books You May Enjoy
  201. Leave a review - let other readers know what you think

Limiting the scope of shell state changes

If you are going to change properties of the shell as a whole in part of your script, consider limiting the scope of that change only to the needed part of the script to avoid unexpected effects on the rest of it. Watch for these in particular:

  • The working directory
  • The positional parameters ($1, $2 ... )
  • Environment variables, especially PATH
  • Shell-local variables, especially IFS
  • Shell options with set (such as -x) or shopt (such as dotglob)
  • Shell resource limits set with ulimit

We already saw one effective means of limiting the scope of variables in Chapter 5, Variables and Patterns, by applying them as prefixes to a command:

IFS=: read -r name address

This limits the scope of the IFS change to the read command only.

For other types of shell state change, we have to get a bit more creative:

  • Keeping the script itself so short that the change doesn't matter
  • Changing the state back to its original value again as soon as possible
  • Making the change in a subshell so that it doesn't affect the rest of the program
  • Rewriting to avoid the change entirely

The last option is by far the most desirable; if the command itself can do what you need, don't reinvent that wheel in Bash!

Here is an example based on a common problem: the following script changes into the working directory of a Git repository in ~/src/bash, and fetches any changes from its default remote branch:

cd -- "$HOME"/src/bash || exit
git fetch

The problem is that the script needs to change its directory to do this, and then needs to change back to whatever directory it started in before proceeding with the rest of the script.

We could do this manually by saving the current working directory in a variable named pwd before changing it to the repository directory, and then changing back to the saved path after we are done:

pwd=$PWD
cd -- "$HOME"/src/bash || exit
git fetch
cd -- "$pwd" || exit

We could make the change in a subshell, so that it does not change the state of the surrounding script; this is complicated, however, as we then need to add an extra exit to catch a failure to change directory at all, and || true to ignore error conditions from git fetch, since that's what the original does:

(
    cd -- "$HOME"/src/bash || exit
    git fetch || true
) || exit

The best method in this case is to use the git program's  -C option to specify the working directory for the command, allowing us to reduce this to just one line:

git -C "$HOME"/src/bash fetch

If you apply a little care to managing global state like this, your scripts will be much easier to edit later.