Table of Contents

1. Filename expansion

Results are expanded on a single line, alphabetically sorted (use echo for debugging)

*              all files
?              where name length == 1
???            where name length == 3
???*           where name length >= 3
[abc]          where name length == 1 and follows pattern
[a-zA-Z0-9]    where name length == 1 and follows pattern
[!a-z]*        negative matching first character and length >= 1
*.[!a-zA-Z]    ends with dot followed by negative matching last character
dir/*          all files in dir
dir/.*         all invisible files in dir
*/*            all files in all visible directories
*/*/*          same as above but 3 levels deep
.*/*           all files in all invisible directories (including . and ..)
.*/.*          all invisible files in all invisible directories (including . and ..)
.[!.]*/.[!.]*  all invisible files in all invisible directories (not including . and ..)

2. Quoting

echo 'hello there'      # hello there
echo hel'lo th'ere      # hello there (quotes shift state)
echo "hello $HOME"      # hello /home/user
echo "hello ${HOME}"    # hello /home/user
echo "hello $(ls -a)"   # hello (dir contents)
echo "hello `ls -a`"    # hello (dir contents)
echo "hello \`ls -a\`"  # hello `ls -a`
echo 'hello \`ls -a\`'  # hello \`ls -a\`
echo `ls -a`            # (dir contents)

3. Magic shell variables

PATH           executable path, searched in order, colon separated
HOME           where cd goes if no argument is specified, set by the login process
IFS            internal field separator, defaults to " \t\n"
PWD            current working directory
0              current executable file name
1..9           parameters to current executable
*              all parameters, space separated regardless of quoting, "$*" represents a string of all parameters
@              same as above, except that quoting is retained on each parameter
#              amount of parameters
$              current pid
!              pid of latest started background process (&)
?              return code of last process

4. Magic shell commands

:              does nothing (useful in if-statements for leaving then-cases empty)

5. Programming and control-flow

5.1. Variables

Allowed variable names: [a-zA-Z0-9_] (first character may not be a number)

VAR="another value"
echo $VAR
echo ${VAR}
A=aaa B=bbb C=ccc; echo $A $B $C
export VAR  # move from "set" to "env/export", child-processes will now inherit the variable
echo ${WAR?variable does not exist}
echo ${WAR?}
echo ${WAR-use me if undefined}
echo ${VAR+use me if defined, else empty}
echo ${WAR=redefine to me if undefined, return redefinition}
# above forms can be replaced with :?, :-, :+ and := to have empty-string and undefined mean the same thing
unset VAR

5.2. Operators

&&               # and, short circuits
||               # or, short circuits
&                # start process in background
;                # separate commands
{ stmt; stmt; }  # group statements
( stmt; stmt )   # same as above, but runs in a subshell, so variables or other state won't transfer over

5.3. If-statements

command-list in this case is either a single command or a list of commands separated by &, ;, &&, ||, | or newline. If the condition returns 0, the then-case happens:

if command-list
elif command-list
elif command-list

5.4. While-statements / Until-statements

Works similar to if-statements, break and continue works like you expect:

while command-list

until command-list

5.5. For-loops

Like in while-statements, break and continue works here too:

for i in a b c d e
    echo "==$i=="

# ==a==
# ==b==
# ==c==
# ==d==
# ==e==

5.6. Cases

Cases use the same pattern syntax as filename expansions:

case $choice in
    yes | YES | y )
        echo YES
    no | NO | n )
        echo NO
    [a-z]* )
        echo Something...
    * )
        echo Anything...

6. Functions

func() {
    echo parameter1=$1 parameter2=$2 etc
    return 0  # if not specified, returns status of the last command

7. Here documents

cat << HERE | grep a