s h i n y b l u e
Bash

Strings {{{

myString=richard
myString="richard lott"
newString=$myString # substitution
newString="hello $myString" # substitution
read myString               # reads from keyboard
read myString < datafile    # reads first line of file
${stringName:a[:b]}         # return [b characters] 
                           starting from a (zero based)
expr 'string1' : 'regexp'   # outputs match of regexp
                            # regexp is invisibly
                            prefixed with ^ ie it always
                            matches from the start.
${stringName/replaceThisSubString/withThis}     #first occurance only
${stringName//replaceThisSubString/withThis}    # all occurances
${stringName/#replaceThisSubString/withThis}    # if found from start
${stringName/%replaceThisSubString/withThis}    # if found at end 
${stringName:-default}  # returns default if stringName is null
${stringName:=default}  # set to default if stringName is null
${stringName#Pattern}   # remove shortest (## longest) 
                          pattern from start (%, %% end)
${stringName%/*}    get directory from full filepath.

}}}

Special Characters {{{

echo understands:

\n  new line
\r  return
\t  tab
\v  vertical tab
\b  backspace
\a  alert (beep / flash)
\0xx    translates xx in octal to ASCII equivalent

also use these like $’\t’ etc. direct on command line. }}}

positional parameters (and arrays) {{{

$0          # script name
$1, $2...$n # parameters
$#          # number of parameters script called with
$*          # all parameters as single word (expansion will have happened)
$@          # as $* except each thing is quoted and not expanded. 
shift           # leaves $0 but makes $1=$2, $2=$3 and so on
set -- $var # parses var and sticks each term in $0, $1..., overwriting the original values
${#foo[@]}  # number of elements in array "foo"

}}}

pid values {{{

$$  # pid of current process
$!  # pid of last started process (eg. started in bg with &) }}}

expansion {{{

r{a,i}ch        # expands to rich and rach
`command`       # expands to result of command, identical to $(command)
`cat file`      # faster is `< file`
$((maths))      # outputs maths expression

word splitting occurs on anything that has been expanded. So echo "$aString" causes $aString to be split }}}

redirection {{{

stdin=0, stdout=1, stderr=2
command 1>/dev/null     #stdout redirected to null (nowhere)
command 2>&1            #stderr appended to stdout
command 1>/dev/null 2>&1    #stdout set up to go nowhere, 
                            #stderr appended to stdout (hence nowhere)
command 2>&1 1>/dev/null    #stderr set up to go to stdout 
                            (before redirection)
                            stdout then set up to go nowhere.
                            ie. errors go out to console, 
                            normal stdout goes nowhere.
command <file   #contents of file used for stdin.

}}}

various {{{

Subshells:

( command; command; )   #runs in a subshell
( command; command; ) & #runs in a subshell in background/parallel
wait                    #wait for subshell to complete

blocks of code:

{ command; command; }

}}}

looping

* note, could use ; instead of new-line. * note, no { }s necessary

FOR loops:

for myvar in "$@"
do
    commands
done

while loops:

while command_or_test
do command
    command2..
done

If construct:

if [ condition ]
then command1
    command2...
elif [ condition ]
then command1
    command2
else    command1
    command2
fi

(select) Case syntax:

case "$variable" in

"$condition1")
commands...
;;

"$condition2")      # use * ) for "case else"
commands...
;;

esac

}}}

Keyboard shortcut commands: {{{

Ctrl+D  # exit shell
Ctrl+C  # terminate line, don't execute
Ctrl+G  # end of line and terminates stdin
Ctrl+U  # erase a line of input
Ctrl+Z  # pause a foreground job 
        (then use commands "bg" and "fg" to control jobs)
Ctrl+S  # freeze screen output. Execution continues 
        but you don't see anything.
Ctrl+Q  # "restart flow" - unfreeze screen

}}}

assignment {{{

var1=whatever       # quote whatever if it has spaces etc.
let "var1=5+2"      # var1=7
((var1=5+2))        #   identical
var1 += 5       # add 5. Also -=
var1=15         # 15 (decmial). Also 017 (octal), 
                0xf (hex), 2#1111 (binary)              }}}

tests {{{

[ things ]      # tests things
[[ things ]]    # tests things which is in an easier to 
                understand and extended format (!)
(( maths ))     # does maths expression, returns zero if 
                maths expression evaluates to 0 
                if maths, eg. 5+4, is non-zero, returns zero
                if maths, eg. 5-5, is zero, returns 1 (!!)
                if maths, eg. 5>4, returns 0 for true and 1 for false

}}}

file test operators {{{

[ -e file1 ]    # file1 exists. ! -e for does not exist 
                (! works with everything, remember the space after it
                Also, if entering from command line, you have to escape
                it, ie $[ ! -e "file1" ] && echo file1 doesn't exist
                )
[ -s file1 ]    # file1 has size>0
[ -d file1 ]    # file1 is a directory. Also -f for regular file
[ f1 -nt f2 ]   # f1 is newer than f2. Also -ot for older than
[ -r file1]     # is f1 readable. 
                Also -x and -w for executable and writable

}}}

integer tests (format, equivalent, explanation) {{{

[ "$a" -eq "$b" ]   N/A                 # equal. also -ne, != for not equal
[ "$a" -gt "$b" ]   [[ "$a" > "$b" ]]   # greater than. also -lt and <
[ "$a" -ge "$b" ]   [[ "$a" >= "$b" ]]  # greater than or equals. 
                                    also -le, <= for less than or equal }}}

string tests - two versions, [] and [[]] {{{

[ "$a" = "$b" ]     [[ "$a" = "$b" ]]   # equal (equivalent is ==). 
                                    Also != for not equal
[ "$a" = blah* ]        NA              # equal with file globbing and 
                                    word splitting
NA                  [[ "$a" = b* ]]     # equal with pattern matching 
                                    (starts with b)
[ "$a" \> "$b" ]    [[ "$a" > "$b" ]]   # greater than in ASCII terms. Also <
[ -z "$a" ]     # is a zero length string (null)    } Note: always quote
[ -n "$a" ]     # is not a zero length string       }   the test string.

}}}

logical operators {{{

[ test1 -a test2 ]  [[ test1 && test2 ]]    # AND. Also -o, || for OR

}}}

chains of commands on one line {{{

this;that       # do this, then that
this && that    # do this, if it returns exit zero, 
                do that (exit status is of that)
this || that    #  do this, if it's non-zero exit, 
                do that  (exit status is of that) }}}

exit status {{{

exit 0-255  # exit with given code
exit            # exit with code from last command
$?          # this gives the exit code of the last command   }}}

colours and bolding in ANSI escape sequences {{{

echo -e -n "whatever"   # the -e turns on recognition of various
              special sequences like \n for new line
              the -n omits the newline at the end

\033[1mhello\033[0  # hello comes out bold.
\033            # start of escape sequence
[           #
1           # turn on bold. Use 4 for underline
m           # end of escape sequence

\033[c1;c2  # turn on background col c2 and foreground c1

c1 values (to use as c2, add 10)
30  black
31  red
32  green
33  yellow
34  blue
35  magenta
36  cyan
37  white

tput sgr0       # ends all this mallarky

}}}

Snippets {{{

reads all lines from txt, splitting on first whitespace into a, then the rest of line into b:

while read a b;do echo "--$a--$b--";done<txt
|--------block-------------------------|

read all processes, output just pids and command names:

ps ax | while read pid b b b fl b;do echo "pid$pid  $fl";done

(**warning**: there are much better ways to do this, this may not work for your distro)

prints message if nmbd found in process list:

ps ax | while read b b b b fl b;do { [[ "$fl" = nmbd* ]] && echo "nmbd ok";  } done;

}}}

lists of things on the command line {{{

in these examples, “-mtime -1” is used but it could be anything:

find th* -mtime -1          # finds (say) this, that
find "th*" -mtime -1        # finds literally (ie. name has * in it)
find `echo "th*"` -mtime -1 # as first example. }}}

quoting on the command line {{{

Syntax: command word1 “word 2” word\ 3 # calls command with three tokens, $1, $2, $3 examples: for token in “$@”;do echo $token;done # this works, its a special case for token in $@;do echo $token;done # this doesn’t work for token in “$*”;do echo $token;done # this prints just one token

copy initial vars into array:

myarray=( "$@" )

then enumerate by:

for token in "${myarray[@]}" ; do echo $token;done

which works the same as “$@” in splitting to “tokens” and it even works for “tokens with\” quotes in” }}}

umasks {{{

See “Start up and profile” below, and see ssh notes. }}}

Start up and profile {{{

* **/etc/profile** put system-wide (environment) stuff here
eg. umask 0002 # owner and group have rw access for new files. * **/etc/bash.bashrc** # system wide for interactive shells
can set umask here too… * **~/.bashrc** # this is run for non-login, interactive shells * **~/.bash_profile* # this is run after login shells.

### A better way to get system-wide umask

(Thanks Charlie for this).

It turns out there’s a PAM module that lets you set a default umask for any system session. So I did apt-get install libpam-umask, and configured /etc/pam.d/common-session so that it had the following line in it:

session optional        pam_umask.so    umask=002

I had a cruise about commenting out or deleting all other references to umask wherever they were.

Next, I wanted ssh to use PAM, so I fiddled with /etc/ssh/sshd_config so it had:

UsePAM yes
PasswordAuthentication no.

Then I restarted ssh. Now any ssh, sftp or login session has a default umask of (0)002 /unless/ you override the default.

}}}

Trapping kill (etc.) signals {{{

Syntax:

trap "command" sigspec

important signals are:

signal  value   action  comment
SIGHUP  1       Term    death of controlling process
                        or handup detected on controlling terminal
SIGINT  2       Term    interrupt from keyboard
SIGQUIT 3       Core    Quit from keyboard (ctrl+c)
SIGKILL 9       Term    Kill signal:
SIG15   15      Term    Termination.

}}}

Zombie processes {{{

Nicked from: http://www.debian-administration.org/articles/261:

ps -A -ostat,ppid,pid,cmd

Gives us all processes , stat[e] p[arent]pid, pid, and c[om]m[an]d like this:

STAT PPID PID CMD
S 0 1 init [3]
SN 1 2 [ksoftirqd/0]
S< 1 3 [events/0]

grep for zombies with something like grep -e '^[Zz]' to be safe

ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'

So here we said:

  1. list all processes,
  2. show me the good stuff, like stat[e] p[arent]pid, pid, and c[om]m[an]d
  3. Then, send the output to grep, because I only want the lines that start with a Z or z .

Now let’s restart the parent processes and shake out the zombie generation. my favorite way is kill -HUP then with the help of our friend the backtick we get

kill -HUP `ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}'`

now the commands read: restart the parent by listing all processes and showing stat,ppid,pid and cmd, grepping out the lines starting with Z or z then using awk to select only the parent pid from the output.

}}}


Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.0 License.