IngmarBoddington
3/21/2013 - 12:51 PM

Notes on shell scripting in Linux. Should be used in conjunction with terminal notes: https://gist.github.com/IngmarBoddington/4226355

Notes on shell scripting in Linux. Should be used in conjunction with terminal notes: https://gist.github.com/IngmarBoddington/4226355

Basics
======

Expansion (special symbols replaced by values) and word splitting (arguments being split into several aruments) must have attemtion paid or pain will follow.

- # for comments

- Lots of internal variables available to bash scripts, see: http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST
    - Name of script will be $0
    - Parameters passed to script will be in $1, $2, $3.... vars and count in $#
    - $? will return last exit message / return code for last command
    - "$*" (with the quotes) returns all script arguments as single value separated by IFS
    - $# number of arguments
    - $@ full list of arguments as IX delimited value
    - "$@" full list of args as seperate words
    - $$ returns processId
    - $- returns processId of last background process
    - ${array[@]}: full array as IFS delimited value
    - "${array[@]}": full array as seperate words

- No line terminators required but convention is semi-colon (EOL works fine)
- Use -e flag for echo's which include control characters (like \n)
- Using double quptes around variable identifiers evades word splitting arguments (single argument becoming many, often causes issues)

sh <script>
    - Run script from terminal 
    - Don't need sh if file made executable to user

#!<commandIntepreter>
    - Put at top of file to point command interpreter for rest of file (normally something like /bin/bash)
    - #!/bin/sh will call the default shell interpreter

<identifier>=<value>;
    - Local scalar assignment (avoid spaces around = operator)

<identifier>=(<spaceDelimitedValues>);
    - List / Array assignment
    - i.e. list=(item1 item2 ...) or list=([key1]=item1 [key2]=item2] ...)

$<identifier>
    - Using assigned variables

exit [<string>]
    - Exit with optional message
    - If message is omitted the last command exit message will be returned / displayed

${<identifier>[<key>]}
    - Get value of element of array

${<identifier>[@]}
    - Return whole array (space delimited)

${#<identifier>[@]}
    - Length of array
    
${#<identifier>}}
    - Length of string
    
Capture output from command
- var=$(<command>);
- OLD: Use backticks for fetch results of bash commands, e.g. `ls` to return list of directory contents
- If failing to capture output from command, try appending  2>&1 to command (redirect stderr to stdout)

Prompting for input example (e.g.):

        while true; do
                read -p "Ignore (I) or Abort (A): " input
                case $input in
                        [iI]* ) break;;
                        [aA]* ) exit;;
                        * ) echo "Please answer Ignore (I) or Abort (A): ";;
                esac;
        done;

IFS="<delimiter>"
    - Use this to change the "Internal Field Separator" from the space default (auto list separator in loops etc)

IFS=$OIFS;
    - Set IFS back to default

When entering a command the order of expansions is: 
brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.

printf "format" <vars>
    - Print formated string with vars interpolated (uses the standard %d, %s etc flags)
    
Control Structures
==================

If-else block:

    if [ <condition> ]; then
        <commands>
    else
        <commands>
    fi;

For block

    for <var> in <list>; do 
        <commands>;
    done;

Case block

    case <expression> in 
        <pattern1> )
            <commands>;;
        ....
    esac;

Function declaration

    function <functionName> {
        <commands>
    }

While block

  while <condition>; do
		<commands
	done;
        
        
Operators / Conditionals
========================

There is no concatenation operator, just put things side-by-side or use string interpolation

Comparison Operators (using 'test' / [)
    Operators - format: [ <expr> <operator> <expr> ]
        - Certain symbols (e.g. < redirect) should be avoided due to double meaning (use new test instead)
        ==  is equal to (can use = instead)
        != is not equal to
        -eq is equal to
        -ne	is not equal to
        -gt	is greater than
        -ge	is greater than or equal to
        -lt	is less than
        -le	is less than or equal to
        [ $a == z* ]  File globbing and word splitting take place.
        [ "$a" == "z*" ]	True if $a is equal to z* (literal matching).
    Unary Operators - format: [ <operator> <expr> ]
        -s (lowercase ‘s’)  file is not zero size
        -f  file is a regular file (not a directory or device file)
        -d  file is a directory
        -e  file exists
        -S	file is a socket
        -b	file is a block device (floppy, cdrom, etc.)
        -c	file is a character device (keyboard, modem, sound card, etc.)
        -p	file is a pipe
        -h	file is a symbolic link
        -L	file is a symbolic link
        -t	file (descriptor) is associated with a terminal device
        -r	file has read permission (for the user running the test)
        -w	file has write permission (for the user running the test)
        -x	file has execute permission (for the user running the test)
        -g	set-group-id (sgid) flag set on file or directory
        -u	set-user-id (suid) flag set on file
        -k	sticky bit set
        -O	you are owner of file
        -G	group-id of file same as yours
        -N	file modified since it was last read
        -n  string is not “null.”
        -z	string is “null, ” that is, has zero length
        f1 -nt f2	file f1 is newer than f2
        f1 -ot f2	file f1 is older than f2
        f1 -ef f2	files f1 and f2 are hard links to the same file

Also have 'new test' / [[ in most distros giving more options
  no longer need to quote to evade word splitting of args
  <  is less than
  <=  is less than or equal to
  >	is greater than
  >=	is greater than or equal
  =~ regular expression matching
  [[ $<identifier = *<string>* ]] - True if string in variable
  


&& (and) and || (or) can be used to join [ ] / [[ ]] conditional blocks

Global Variables
================

    BASH_VERSION: Contains a string describing the version of Bash.
    HOSTNAME: Contains the hostname of your computer, I swear. Either short or long form, depending on how your computer is set up.
    PPID: Contains the PID of the parent process of this shell.
    PWD: Contains the current working directory.
    RANDOM: Each time you expand this variable, a (pseudo)random number between 0 and 32767 is generated.
    UID: The ID number of the current user. Not reliable for security/authentication purposes, alas.
    COLUMNS: The number of characters that fit on one line in your terminal. (The width of your terminal in characters.)
    LINES: The number of lines that fit in your terminal. (The height of your terminal in characters.)
    HOME: The current user's home directory.
    PATH: A colon-separated list of paths that will be searched to find a command, if it is not an alias, function, builtin command, or shell keyword, and no pathname is specified.
    PS1: Contains a string that describes the format of your shell prompt.
    TMPDIR: Contains the directory that is used to store temporary files (by the shell).