Interesting bash aliases and functions:

Neat features

Edit a command in $EDITOR

Ctrl-x Ctrl-e will edit a command in $EDITOR before execution.

With set -o vi in bash/readline, v in command mode will do the same.

-v for testing set variables, while handling undefined ones

-v: True if the shell variable varname is set (has been assigned a value).

bash >=4.2 supports -v for testing for *set* variables while handling empty ones, also no specials needs when running under 'set -u':

   1 % cat foo
   2 FOO=''
   3 [ -z "${FOO:-}" ] && echo 1
   4 [ -z "${BAR:-}" ] && echo 2
   5 [ -v FOO ] && echo 3
   6 [ -v BAR ] && echo 4
   7 % bash -u ./foo
   8 1
   9 2
  10 3

source

also:

If you use bash, you should really use ]] instead of [ ]. It can do everything [ can (and then some, like ERE and glob matches), but is a shell keyword, which improves ergonomics quite a bit. See [ $x = 0 ] vs. [[ $x = 0 after unset x, for example.

Special Variables

See Special Parameters from the Bash Reference Manual.

"Strict Mode"

Tools

Use shellcheck with timonwong.shellcheck plugin.

Use bash-language-server.

Gotchas

Types and variables

Can use declare (conventional r/w variable), local (scoped to function only), and readonly, along with modifiers (e.g. -a), to declare variables.

E.g. readonly -a declares a read-only array.

Arrays

   1 # Define
   2 arr=("one" "two")
   3 declare -a arr=("one" "two")
   4 
   5 # Append
   6 arr+=("three")
   7 
   8 # Merge all items, space delimited
   9 echo "${arr[@]}"
  10 # one two three
  11 
  12 # Join by delimiter
  13 echo $(IFS=, ; echo "${arr[*]}")
  14 # one,two,three
  15 
  16 # Indexes of the array (i.e. Python's enumerate)
  17 echo "${!arr[@]}"
  18 # 0 1 2
  19 
  20 # Array length
  21 echo "${#arr[@]}"
  22 # 3
  23 
  24 # Remove an element
  25 unset arr[3]
  26 
  27 # Display item by position
  28 echo "${arr[1]}"
  29 # two
  30 
  31 # Loop over each individual items
  32 # If inside a quoted string
  33 # '@' returns each individual item
  34 for i in "${arr[@]}"; do
  35   echo "$i"
  36 done
  37 # one
  38 # two
  39 # three
  40 
  41 # If inside a quoted string
  42 # '*' will merge together by IFS
  43 for i in "${arr[*]}"; do
  44   echo "$i"
  45 done
  46 # one two three
  47 
  48 # Copy an array
  49 declare -a arr2=("${arr[@]}")
  50 
  51 # Combine two arrays
  52 declare -a arr3=("${arr1[@]}" "${arr2[@]}")
  53 
  54 # Randomly shuffle an array
  55 shuf -e "${arr[@]}"
  56 shuffled=(shuf -e "${arr[@]}")
  57 
  58 # Delete an entire array
  59 unset arr arr1 arr2 arr3
  60 
  61 # Subset of an array
  62 # ${arr[@]:$start} # from start to end of array
  63 # ${arr[@]::$count} # first count-many elements from beginning
  64 # ${arr[@]:$start,$count} # count-many elements from start
  65 echo "${arr[@]:1:1}"
  66 
  67 # Check if array is empty
  68 if [[ ${#arr[@]} -eq 0 ]]; then ... fi
  69 
  70 # Check if array is not empty
  71 if [[ ${#arr[@]} -gt 0 ]]; then ... fi
  72 
  73 # Check item "one" is in array
  74 [[ ${arr[*]} =~ ^|[[:space:]])"one"($|[[:space:]]) ]] && echo "exists" || echo "doesn't exist"
  75 # exists
  76 
  77 # Check if partial match is in array
  78 [[ ${arr[*]} =~ 'on' ]] && echo "exists" || echo "doesn't exist"
  79 # exists
  80 
  81 # Read into an array from a file, safely. Preserves spaces, special characters, etc.
  82 # bash 4.0
  83 mapfile -t inputarr < file.txt
  84 
  85 # Read into an array from a command, safely. Preserve spaces, special characters, etc.
  86 # -t removes trailing spaces
  87 readarray -t inputarr < <(seq 5)
  88 declare -p inputarr
  89 # declare -a inputarr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")
  90 

Associative arrays/hash tables

declare -A ht
ht["one"]=1
ht["two"]=2

# Print values, all one line
echo "${ht[@]}"
# 2 1

# Print keys, all one line
echo "${!ht[@]}"
# two one

# Iterate over keys and values
for k in "${!ht[@]}"; do
  echo "$k=${ht[$k]}"
done
# two=2
# one=1

# Hash length
echo "${#ht[@]}"

# Remove a key
unset ht["one"]
echo "${ht[@]}"
# 2

# Check if key is in hash
[[ -z "${ht["one"]}" ]] && echo "exists" || echo "doesn't exist"

Escaping characters

tl;dr: bash (TODO: check which version) lets you just use the character via copy-and-paste. Make sure to be using a Unicode encoding, e.g. LANG="en_US.UTF-8".

Use special `$"..." quoting to allow bash to read ANSI C and Unicode escapes. E.g.

# ANSI escape
VAR=$'\xe2\x98\xa2'
# Unicode escape
VAR=$'\u2622'

See also: ANSI-C quoting from the Bash Reference Manual.

Never Remember

Process Substition is the name for <(command) syntax.

Redirect stderr to stdout with 2>&1, e.g.:

Some-Command 2>&1 > log.txt