Bash Command Practice
Bash is the shell and scripting language you interact with on every Linux host. This track drills the syntax you look up most: parameter expansion operators (${VAR:-val}, ${VAR%suffix}), special variables ($?, $!, $$), redirection operators, test conditions ([[ -z ]]), and set -o options — the fragments that are one character off from being wrong.
Command Reference
history
| Command | Description |
|---|---|
!! | Re-execute the most recently run command. |
!$ | Expand to the last argument of the most recent command. |
!<n> | Re-execute the nth command from history. |
!-<n> | Re-execute the nth most recently run command relative to now. |
!$:t | Expand to the basename of the last argument from the most recent command. |
!$:h | Expand to the directory portion of the last argument from the most recent command. |
!!:s/<from>/<to>/ | Replace the first occurrence of 'from' with 'to' in the most recent command and run it. |
!!:gs/<from>/<to>/ | Replace all occurrences of 'from' with 'to' in the most recent command and run it. |
parameter
| Command | Description |
|---|---|
${<VAR>:-<val>} | Expand to $VAR if set and non-empty; otherwise expand to val without assigning it to VAR. |
${#<VAR>} | Expand to the number of characters in the value of $VAR. |
${<VAR>:=<val>} | Expand to $VAR if set and non-empty; otherwise assign val to VAR and expand to it. |
${<VAR>:+<val>} | Expand to val if VAR is set and non-empty; otherwise expand to nothing. |
${<VAR>:?<message>} | Expand to $VAR if set and non-empty; otherwise print message to stderr and exit the script. |
${<VAR>%<suffix>} | Remove the shortest matching suffix pattern from the end of $VAR. |
${<VAR>%%<suffix>} | Remove the longest matching suffix pattern from the end of $VAR. |
${<VAR>#<prefix>} | Remove the shortest matching prefix pattern from the start of $VAR. |
${<VAR>##<prefix>} | Remove the longest matching prefix pattern from the start of $VAR. |
${<VAR>/<from>/<to>} | Replace the first occurrence of 'from' with 'to' inside $VAR. |
${<VAR>//<from>/<to>} | Replace all occurrences of 'from' with 'to' inside $VAR. |
${<VAR>:<offset>:<length>} | Expand to a substring of $VAR starting at offset for length characters. |
redirection
| Command | Description |
|---|---|
<command> > <file> | Redirect stdout of a command to a file, overwriting it if it exists. |
<command> >> <file> | Append stdout of a command to a file without overwriting existing content. |
<command> 2> <file> | Redirect stderr of a command to a file. |
<command> 2>/dev/null | Discard stderr by redirecting it to /dev/null. |
<command> < <file> | Feed a file to a command's stdin. |
<command> 2>&1 | Redirect stderr to the same destination as stdout. |
<command> &>/dev/null | Discard both stdout and stderr by redirecting all output to /dev/null. |
cat <<END
<text>
END | Feed an inline heredoc block to a command's stdin. |
options
| Command | Description |
|---|---|
set -o errexit | Exit the script immediately if any command returns a non-zero status. |
shopt -s globstar | Allow '**' to match files and directories recursively across path components. |
set -o noclobber | Prevent redirection from overwriting existing files. |
set -o pipefail | Make a pipeline fail if any command in it fails, not just the last one. |
set -o nounset | Treat references to unset variables as an error and exit. |
set -euo pipefail | Enable strict mode: exit on error, treat unset variables as errors, and fail pipelines on partial failure. |
shopt -s nullglob | Remove non-matching glob patterns from the argument list instead of passing them literally. |
shopt -s failglob | Cause non-matching glob patterns to produce an error instead of being passed literally. |
shopt -s nocaseglob | Make glob pattern matching case-insensitive. |
shopt -s dotglob | Include dotfiles in glob expansions (files starting with '.'). |
special-vars
| Command | Description |
|---|---|
$0 | Hold the name or path of the currently executing script or shell. |
$# | Hold the number of positional parameters passed to the script or function. |
$? | Hold the exit status of the most recently executed foreground command (0 = success). |
$1 | Hold the first positional parameter passed to the script or function. |
$! | Hold the PID of the most recently started background task. |
$$ | Hold the PID of the current shell process. |
$@ | Expand to all positional parameters as separate quoted words. |
$* | Expand to all positional parameters joined into a single word separated by IFS. |
$_ | Hold the last argument of the previous command. |
conditions
| Command | Description |
|---|---|
[[ -z <str> ]] | Test that a string is empty (zero length). |
[[ -n <str> ]] | Test that a string is non-empty (non-zero length). |
[[ <str1> == <str2> ]] | Test that two strings are equal. |
[[ -e <file> ]] | Test that a file or directory exists at the given path. |
[[ -d <file> ]] | Test that a path exists and is a directory. |
[[ -f <file> ]] | Test that a path exists and is a regular file (not a directory or device). |
[[ <num1> -lt <num2> ]] | Test that the first integer is less than the second. |
[[ <num1> -eq <num2> ]] | Test that two integers are equal. |
[[ <num1> -ne <num2> ]] | Test that two integers are not equal. |
[[ <str> =~ <pattern> ]] | Test that a string matches an extended regular expression. |
[[ -r <file> ]] | Test that a file exists and is readable by the current process. |
[[ -w <file> ]] | Test that a file exists and is writable by the current process. |
[[ -x <file> ]] | Test that a file exists and is executable by the current process. |
Key Use Cases
- Substitute a default value when a variable is unset
- Strip a filename extension or directory prefix from a path variable
- Route stderr to a log file while keeping stdout on screen
- Check a command exit status with $? after it runs
- Enable strict mode to catch unbound variables and pipeline failures
- Test whether a file exists or is writable before acting on it
Frequently Asked Questions
What is the difference between ${VAR:-val} and ${VAR:=val}?
:- returns val if VAR is unset or empty, but does not change VAR. := both returns val and assigns it to VAR if VAR is unset or empty. Wrong operator is a different expression on this track.
What does $? hold?
$? holds the exit status of the most recently executed foreground command. 0 means success; anything else is failure. It is reset by every command, so save it immediately if you need it later.
What is the difference between 2>&1 and &>?
2>&1 redirects file descriptor 2 (stderr) to wherever fd 1 (stdout) currently points. &>/dev/null redirects both stdout and stderr together. Order matters: cmd > file 2>&1 sends both to file; cmd 2>&1 > file only redirects stdout.
When should I use set -euo pipefail?
-e exits on error, -u treats unset variables as an error, -o pipefail makes a pipeline fail if any command in it fails. Together they make scripts fail fast instead of silently continuing past broken state.
Ready to master Bash commands?
Test your muscle memory with our spaced-repetition quiz system. Free forever.
