[ expr ] vs. [[ expr ]]
Always quoteSafer/handles spaces
Word splittingNo word splitting
Filename expansionNo filename expansion
/usr/bin/test (Posix)Keyword (Bash, zsh...)
Unquotted pattern match *, ?, []
Unquotted logic comb. &&, ||, !
Unquotted pattern match =~ regex

( sub-shell ) vs. { curr-shell }

( command1; command2 ... ) Groups commands in a subshell. Isolated variable scope. Within a new process. { command1; command2 ... } Groups commands in the current shell. Keeps scope, can change variables. Re-uses the same process.
File Conditions
[[ -a file ]] (also, -e)exists
[[ -b file ]]is a block-special
[[ -c file ]]is a character-special
[[ -d file ]]is a directory
[[ -f file ]]is a regular file
[[ -p file ]]is a pipe/FIFO
[[ -S file ]]is a socket
[[ -h file ]] (also, -L)is a symlink
[[ -r file ]]perm readable
[[ -w file ]]perm writable
[[ -x file ]]perm executable
[[ -u file ]]has user-id bit
[[ -g file ]]has group-id bit
[[ -k file ]]has sticky bit
[[ -s file ]]non-zero size
[[ -N file ]]modified since last read
[[ -O file ]]user ownership
[[ -G file ]]user group-id
[[ -t file-descriptor ]]ref to open terminal
String Conditions
[[ -n expr ]]length non-zero
[[ -v varname ]](also, -R)defined
[[ -z expr ]]empty / length zero
[[ expr == pattern ]] (also, =)matches
[[ expr != pattern ]]doesn't match
[[ expr =~ pattern ]]matches (regex)
Integer Conditions
[[ expr -gt expr ]]greater than
[[ expr -lt expr ]]less than
[[ expr -ge expr ]]greater than or equal to
[[ expr -le expr ]]less than or equal to
[[ expr -eq expr ]]equal
[[ expr -ne expr ]]not equal
Logical Conditions
[[ ! expr ]] negation
[[ expr && expr ]] intersection
[[ expr || expr ]] union

IFS, the Internal Field Separator

The shell uses this to determine how to do word splitting i.e. separate fields. In this example, it is changed to commas. It may be used to parse CSV, TSV, and generally semi-structured mark-up with a simple field separation scheme.

  mystring="one two,three;four"
  IFS=','
  for word in $mystring; do echo $word; done
  
  one two
  three;four
  

Looping on files or lines, using IFS, with while loops.

Snippet making a for loop iterate over the output of find. This will trip shellcheck, warning that using for is fragile over the output of find. The reason is that if the current IFS is included in a filename, the loop will treat it as two separate items, causing unintended behaviours.

  for file in "$(find .)"; do
    echo "$file"
  done
  

Another syntax, less readable, but more inline

  find . -print0 | while IFS= read -rd '' file; do \
    echo "$file"; done
  

By using the flag -print0, making find separate the filenames with a null character (a zero byte).

Note: Piping find -print0 into xargs calls for using xargs flag -0, standard operation.

read reads stdin one byte at a time, until it finds an unescaped newline character, or end-of-input.

When doing IFS= read -r line, IFS is first set to an empty string. Therefore no splitting will occur. The special syntax VAR=value command args, makes the IFS change only affect that statement, any following commands isn't affected. Therefore read reads the whole line, assigning it to the first variable $line.