Bash Scripting Tricks

author: Nathan Acks

# Brace expansion
#
{X,Y}      # X Y
{X,Y}.txt  # X.txt Y.txt
{1..10}    # 1 2 3 4 5 6 7 8 9 10
{1..10..2} # 1 3 5 7 9

# Special variables
#
$#   # Number of arguments to script/function
$1   # First argument
$9   # Ninth argument (NOTE: there is no $10 and higher)
"$@" # All arguments as a separate quoted strings
"$*" # All arguments as a single string separated by
     # first IFS character

# IFS is the string of characters that act as delimeters
# (for example, in loops). If unset, it's equal to the
# sequence <space><tab><newline>.

# Length of a variable
#
MYVAR=/path/to/file/file.tar.gz
${#MYVAR} # 25

# Variable manipulation
#
${MYVAR%.*}            # /path/to/file/file.tar
${MYVAR%%.*}           # /path/to/file/file
${MYVAR#*/}            # path/to/file/file.tar.gz
${MYVAR##*/}           # file.tar.gz
${MYVAR/file/newfile}  # /path/to/newfile/file.tar.gz
${MYVAR//file/newfile} # /path/to/newfile/newfile.tar.gz
${MYVAR:1:4}           # path
${MYVAR:(-6):3}        # tar

# Setting defaults
#
${MYVAR:-default} # Return $MYVAR, or "default" if unset
${MYVAR:=default} # Set $MYVAR to "default" if unset
${MYVAR:+default} # Return "default" if $MYVAR set
${MYVAR:?error}   # Exit with "error" if $MYVAR unset

# Variable variables
#
VAR1="Hello world"
VAR2="VAR1"
${!VAR2} # Hello world

# Arrays
#
MYARRAY=("element0" "element1" "element2")
MYARRAY[3]="element3"
${MYARRAY[0]}     # element0
${MYARRAY[-1]}    # element3
${MYARRAY[@]}     # element0 element1 element2 element3
${MYARRAY[@]:1:2} # element1 element2
${!MYARRAY[@]}    # 0 1 2 3

# Size of an array
#
${#MYARRAY[@]} # 4

# Remove an element from an array
#
unset MYARRAY[3]

# Arrays are actually a special case of dictionaries,
# which hold key/value pairs. In an array, keys are just
# 0-indexed numbers. Dictionaries work exactly the same
# as arrays, except rather than referencing/setting
# elements by number, you reference and set them by key.

# Create a dictionary
#
declare -A MYDICT

# Math
#
$(( 1 + 2 )) # 3
$RANDOM      # Random-ish number

# Loop over lines in a file
#
cat $FILE | while read LINE; do
	# Do stuff with $LINE
done

# Loop over filenames with spaces
#
while IFS= read -d '' -r FILE; do
	# Do stuff with $FILE
done < <(find $DIR -type f -print0)

# The advantage this has over other approaches is that it
# doesn't create a subshell, so you can use variables set
# within the loop elsewhere. We need to temporarily
# override IFS because our list is null-separated; the
# space between the -d and the '' (an empty string, which
# Bash interprets as the null character) is *required*.