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 {{{
- note: you should always “quote” all filenames.
[ -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 {{{
- Warning: tends to mess up editing of command lines which get long enough to wrap.
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:
- list all processes,
- show me the good stuff, like stat[e] p[arent]pid, pid, and c[om]m[an]d
- 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.
}}}
