Bash Scripting Basics for HPC Users
Bash Scripting Basics for HPC Users
2
Guide To This Presentation
• These lines are narrative information
• Beige boxes are interactive terminal sessions:
$ echo Today is $(date)
3
Terminal Emulators
• PuTTY ([Link]
• iTerm2 ([Link]
• NoMachine ([Link]
• MobaXterm ([Link]
4
Connect to Biowulf
• open terminal window on desktop, laptop
$ ssh user@[Link]
5
Start Interactive Session
6
Copy Examples
• Create a working directory
mkdir bash_class
cd bash_class
7
Copy Examples
• Not on Helix/Biowulf:
mkdir bash_class
cd bash_class
curl \
[Link] \
> [Link]
tar -x -z -f [Link]
8
HISTORY AND INTRODUCTION
9
Bash
• Bash is a shell, like Bourne, Korn, and C
• Written and developed by the FSF in 1989
• Default shell for most Linux flavors
10
Definitive References
• [Link]
ual/
• [Link]
• [Link]
11
Bash on HPC
• All machines within HPC run Bash v4.2.46
12
You might be using Bash already
$ ssh user@[Link]
...
Last login: Wed Aug 10 12:27:09 2018 from
[Link]
$ echo $SHELL
/bin/bash
$ bash
13
What shell are you running?
• You should be running bash:
$ echo $0
-bash
14
Shell, Kernel, What?
user
screen
keyboard
applications
SHELL
kernel
15
ESSENTIALS
16
*nix Prerequisite
• It is essential that you know something about
UNIX or Linux
• Introduction to Linux (Helix Systems)
• [Link]
• Linux Tutorial at TACC
• Linux Tutorial at TLDP
17
Elemental Bash
• Bash is a command processor: interprets
characters typed on the command line and
tells the kernel what programs to use and how
to run them
• AKA command line interpreter (CLI)
18
POTPOURRI OF COMMANDS
19
Simple Command
simple command
20
Essential *nix Commands
cd ls pwd file wc find du
21
Comprehensive List
• [Link]
g_LinuxCommands.pdf
22
DOCUMENTATION
23
Documentation
• [google]
• info
• man
• help
• type
• --help
24
Documentation: info
• info is a comprehensive commandline
documentation viewer
• displays various documentation formats
$ info kill
$ info diff
$ info read
$ info strftime
$ info info
25
Documentation: man
$ man pwd
$ man diff
$ man head
26
Documentation: type
• type is a builtin that displays the type
of a word
$ type -t rmdir
file
$ type -t if
keyword
$ type -t echo
builtin
$ type -t module
function
$ type -t ls
alias
27
builtin
• Bash has built-in commands (builtin)
• echo, exit, hash, printf
28
Documentation: builtin
• Documentation can be seen with help
$ help
29
Non-Bash Commands
• Found in /bin, /usr/bin, and
/usr/local/bin
• Some overlap between Bash builtin and
external executables
$ help time
$ man time
$ help pwd
$ man pwd
30
--help, -h
• Many commands have (or should have) a help
menu
$ find --help
31
SCRIPTS
32
Why write a script?
• One-liners are not enough
• Quick and dirty prototypes
• Maintain library of functional tools
• Glue to string other apps together
• Batch system submissions
33
What is in a Script?
• Commands
• Variables
• Functions
• Loops
• Conditional statements
• Comments and documentation
• Options and settings
34
My Very First Script
• create a script and inspect its contents:
echo 'echo Hello World!' > hello_world.sh
cat hello_world.sh
• results:
$ bash hello_world.sh
Hello World!
35
Multiline file creation
• create a multiline script:
$ cat << ALLDONE > hello_world_multiline.sh
> echo Hello World!
> echo Yet another line.
> echo This is getting boring.
> ALLDONE
$
$ bash hello_world_multiline.sh
Hello World!
Yet another line.
This is getting boring.
$
36
nano file editor
37
Other Editors
• SciTE
• gedit
• nano and pico
• vi, vim, and gvim
• emacs
• Use dos2unix if text file created on
Windows machine
38
Execute With A Shebang!
• If bash is the default shell, making it
executable allows it to be run directly
chmod +x hello_world.sh
./hello_world.sh
#!/bin/bash
echo Hello World!
39
Debugging
• Call bash with -x -v
bash -x -v hello_world.sh
#!/bin/bash -xv
echo Hello World!
40
A Word About The Shebang
• The shebang allows only one argument
#!/bin/bash -xv
echo Hello World!
• is ok
#!/bin/bash -x -v
echo Hello World!
• is not ok
41
examples/input/[Link]
42
Special Parameters - Positional
• Positional parameters are arguments passed
to the shell when invoked
• Denoted by ${digit}, > 0
$ cat [Link]
#!/bin/bash
echo ${4} ${15} ${7} ${3} ${1} ${20}
$ bash [Link] {A..Z}
D O G C A T
43
Shell Parameters - Special
44
SETTING THE ENVIRONMENT
45
Environment
• A set of variables and functions recognized by
the kernel and used by most programs
• Not all variables are environment variables,
must be exported
• Initially set by startup files
• printenv displays variables and values in
the environment
• set displays ALL variable
46
Variables
• A variable is construct to hold information,
assigned to a word
• Variables are initially undefined
• Variables have scope
• Variables are a key component of the shell's
environment
47
Using Variables
• A simple script:
#!/bin/bash
cd /path/to/somewhere
mkdir /path/to/somewhere/test1
cd /path/to/somewhere/test1
echo 'this is boring' > /path/to/somewhere/test1/file1
declare myvar=100
myvar=10
49
Set a variable
• Examine value with echo and $:
$ echo $myvar
10
50
export
• export is used to set an environment
variable:
MYENVVAR=10
export MYENVVAR
printenv MYENVVAR
51
unset a variable
• unset is used for this
unset myvar
$ export HOME=/home/user
52
Remove from environment
• export -n
$ declare myvar=10
$ echo $myvar
10
$ printenv myvar # nothing – not in environment
$ export myvar
$ printenv myvar # now it's set
10
$ echo $myvar
10
$ export -n myvar
$ printenv myvar # now it's gone
$ echo $myvar
10
53
Bash Variables
• $HOME = /home/[user] = ~
• $PWD = current working directory
• $PATH = list of filepaths to look for
commands
• $TMPDIR = temporary directory (/tmp)
• $RANDOM = random number
• Many, many others…
54
printenv
$ printenv
HOSTNAME=[Link]
TERM=xterm
SHELL=/bin/bash
HISTSIZE=500
SSH_CLIENT=[Link] 52018 22
SSH_TTY=/dev/pts/274
HISTFILESIZE=500
USER=student1
55
module
• module can set your environment
module load python/2.7
module unload python/2.7
[Link]
56
Setting Your Prompt
• The $PS1 variable (primary prompt, $PS2
and $PS3 are for other things)
• Has its own format rules
• Example:
PS1="[\u@\h \W]$ "
57
Setting Your Prompt
• \d date ("Tue May 6")
• \h hostname ("helix")
• \j number of jobs
• \u username
• \W basename of $PWD
• \a bell character (why?)
[Link]
[Link]
58
COMMAND LINE INTERPRETER
59
Watch What You Write
• Bash interprets what you write after you hit
return
• Patterns of characters can cause expansion
60
Parameter Expansion
• $ is placed outside for parameter expansion
name=monster
echo $name
monster
echo ${name}_silly
monster_silly
61
Parameter Expansion
cookie_monster_is_silly
62
Brace Expansions
• Brace expansion { , , }
echo {bilbo,frodo,gandalf}
echo {0,1,2,3,4,5,6,7,8,9}
0 1 2 3 4 5 6 7 8 9
63
Brace Expansions
• Brace expansion { .. }
echo {0..9}
0 1 2 3 4 5 6 7 8 9
$ echo {b..g}
b c d e f g
echo {bilbo..gandalf}
{bilbo..gandalf}
64
Brace Expansions
• Nested brace expansions
mkdir z{0,1,2,3,4,5,6,7,8,9}
ls
z0 z1 z2 z3 z4 z5 z6 z7 z8 z9
rmdir z{{1..4},7,8}
ls
z0 z5 z6 z9
65
Brace Expansions
• Distinct from parameter expansion $ or ${
echo {$var1,${name},brought,to,you,by,{1..3}}
66
Arithmetic Expansion
• (( )) is used to evaluate math
• $ is placed outside for parameter expansion
echo ((12-7))
echo $((12-7))
67
Arithmetic Expansion
• Variables can be updated, not just evaluated
a=4
b=8
echo $a
echo $b
echo $((a+b))
12
68
Arithmetic Expansion
• Variables can be updated, not just evaluated
echo $a
echo $b
echo $((a=a+b))
12
echo $a
12 69
Arithmetic Expansion
• The ++ and -- operators only work on
variables, and update the value
a=4
((a++))
echo $a
unset b
((b--))
echo $b
-1
70
Arithmetic – integers only
• Bash can only handle integers
a=4.5
((a=a/3))
71
Arithmetic – integers only
• Bash can only do integer math
a=3
((a=a/7))
echo $a
72
Arithmetic Expansion
• Math is done using let and ‘(( ))’
$ a=1
$ echo $a
1
$ let a++
$ echo $a
2
$ ((a++))
$ echo $a
3
$ let a=a+4
$ echo $a
7
73
Command Substitution
• ` = backtick
• better to use $()
echo uname -n
uname –n
[Link]
[Link]
74
Command Substitution
• Nested processes
y=$(wc -l $(find scripts/ -type f) | tail -n 1)
echo $y
633 total
75
Tab Expansion
76
Tilde Expansion
$ echo ~
/home/user
77
Quotes
• Single quotes preserve literal values
echo 'cd $PWD $(uname -n)'
cd $PWD $(uname -n)
cd /home/user [Link]
78
Quotes
• Double quotes also preserve blank characters
$ msg=$(echo Hi$'\t'there.$'\n'How are you?)
$ echo $msg
Hi there. How are you?
$ echo "$msg"
Hi there.
How are you?
tab, not space
• use $'\t' to insert a tab
• use $'\n' to insert a newline
79
Escapes
• The escape character ‘\’ preserves literal
value of following character
echo \$PWD is $PWD
$PWD is /home/user
80
Escapes
• Funny non-printing characters
• $'char'
echo Hello World
Hello World
echo $'\n\n'Hello$'\t\t'World$'\n\n'
Hello World
81
ARRAYS
82
What is an array
• An array is a linear, ordered set of values
• The values are indexed by integers
83
Arrays
• Arrays are indexed by integers (0,1,2,…)
array=(apple pear fig)
$ echo ${array[*]}
apple pear fig
$ echo ${array[2]}
fig
$ echo ${#array[*]}
3
84
Arrays vs. Variables
• Arrays are actually just an extension of
variables
$ var1=apple
$ echo $var1
apple
$ echo ${var1[0]}
apple
$ echo ${var1[1]}
$ echo ${#var1[*]}
1
$ var1[1]=pear
$ echo ${#var1[*]}
2
85
Arrays vs. Variables
• Unlike a variable, an array CAN NOT be
exported to the environment
• An array CAN NOT be propagated to subshells
86
Arrays and Loops
• Arrays are very helpful with loops
for i in ${array[*]} ; do echo $i ; done
apple
pear
fig
87
Using Arrays
• The number of elements in an array
num=${#array[@]}
88
Arrays * vs @
• * concatenates all elements when quoted
$ for i in ${array[*]}; do echo $i ; done
apple
pear
fig
$ for i in ${array[@]}; do echo $i ; done
apple
pear
fig
$ for i in "${array[*]}"; do echo $i ; done
apple pear fig
$ for i in "${array[@]}"; do echo $i ; done
apple
pear
fig
89
Careful thinking
• Add one more tricky element
array+=("blood orange")
90
examples/arrays/[Link]
declare -a array
array=(apple pear fig)
91
ASSOCIATIVE ARRAYS
92
Associative Arrays
• Unordered, indexed collection of values
assoc_array
93
Associative Arrays
• Indexed by strings instead of integers, requires
declare -A
declare -A assoc_array=([huey]=red [dewie]=blue
[louie]=green)
• Ordering is lost
95
examples/arrays/assoc_array.sh
96
Associative Array
• If ordering is important, will need to maintain
both regular and associative array
97
ALIASES AND FUNCTIONS
98
Aliases
• A few aliases are set by default
$ alias
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto’
alias edit='nano'
99
Aliases
• Aliases belong to the shell, but NOT the
environment
• Aliases can NOT be propagated to subshells
• Limited use in scripts
• Only useful for interactive sessions
100
Aliases Within Scripts
• Aliases have limited use within a script
• Aliases are not expanded within a script by
default, requires special option setting:
$ shopt -s expand_aliases
101
Functions
• functions are a defined set of commands
assigned to a word
$ status
Thu Aug 18 14:06:09 EDT 2016
14:06:09 up 51 days, 7:54, 271 users, load average: 1.12, 0.91, 0.86
user pts/128 2013-10-17 10:52 ([Link])
Mount Used Quota Percent Files Limit
/data: 92.7 GB 100.0 GB 92.72% 233046 6225917
/home: 2.2 GB 8.0 GB 27.48% 5510 n/a
102
Functions
• display what functions are set:
declare -F
status ()
{
date;
uptime;
who | grep --color $USER;
checkquota
}
103
Functions
• functions can propagate to child shells using
export
export -f status
104
Functions
• unset deletes function
unset status
105
Functions
• local variables can be set using local
$ export TMPDIR=/tmp
$ function processFile {
> local TMPDIR=/data/user/tmpdir
> echo $TMPDIR
> sort $1 | grep $2 > $[Link]
> }
$ processFile /path/to/file string
/data/user/tmpdir
$ echo $TMPDIR
/tmp
106
Three ways to leave a function
• nothing (default)
function test1 { echo test1; }
• return
function test2 { echo test2; return; }
• exit (danger!)
function test3 { echo test3; exit; }
107
Location of function in script
• A function must be defined prior to call
function doSomething
{
echo using $1
}
doSomething
108
examples/functions/[Link]
function throwError
{
echo ERROR: $1
exit 1
}
tag=$USER.$RANDOM
throwError "No can do!"
mkdir $tag
cd $tag
109
LOGIN
110
Logging In
• ssh is the default login client
$ ssh $USER@[Link]
111
ssh login
bash
/etc/profile
/etc/profile.d/*
~/.bash_profile
Bash Flow
~/.bash_login
~/.profile
user session
bash
interactive non-login
interactive login /etc/bashrc
~/.bashrc
non-interactive
user session
background
background
bash script
background
$BASH_ENV
script process
user session
exit
user session
~/.bash_logout
logout exit
112
Logging In
• Interactive login shell (ssh from somewhere
else)
/etc/profile
~/.bash_profile
113
source and .
• source executes a file in the current shell
and preserves changes to the environment
• . is the same as source
• Legacy from Bourne shell
114
~/.bash_profile
cat ~/.bash_profile
PATH=$PATH:$HOME/bin
export PATH
115
Non-Login Shell
• Interactive non-login shell (calling bash from
the commandline)
• Retains environment from login shell
~/.bashrc
• Shell levels seen with $SHLVL
$ echo $SHLVL
1
$ bash
$ echo $SHLVL
2
116
~/.bashrc
cat ~/.bashrc
# .bashrc
117
Non-Interactive Shell
• From a script
• Retains environment from login shell
$BASH_ENV (if set)
118
Arbitrary Startup File
• User-defined (e.g. ~/.my_profile)
$ source ~/.my_profile
[dir user]!
$ . ~/.my_profile
[dir user]!
119
examples/functions/[Link]
source function_depot.sh
tag=$USER.$RANDOM
throwError "No can do!"
cd $tag
120
SIMPLE COMMANDS
121
Definitions
Command word
process
122
Some command examples
• What is the current time and date?
date
123
Simple Command
simple command
124
Simple commands
• List the contents of your /home directory
ls -l -a $HOME
no
Execute
builtin?
Word yes command
expansion
no
hit return
yes
In $PATH
$ cmd arg1 arg2 ERROR
no
126
Process
• A process is an executing instance of a simple
command
• Can be seen using ps command
• Has a unique id (process id, or pid)
• Belongs to a process group
127
top command
128
ps command
129
history
• The history command shows old
commands run:
$ history 10
594 12:04 pwd
595 12:04 ll
596 12:06 cat ~/.bash_script_exports
597 12:06 vi ~/.bash_script_exports
598 12:34 jobs
599 12:34 ls -ltra
600 12:34 tail run_tophat.out
601 12:34 cat run_tophat.err
602 12:54 history 10
130
history
• HISTTIMEFORMAT controls display format
$ export HISTTIMEFORMAT='%F %T '
$ history 10
596 2018-10-16 12:06:22 cat ~/.bash_script_exports
597 2018-10-16 12:06:31 vi ~/.bash_script_exports
598 2018-10-16 12:34:13 jobs
599 2018-10-16 12:34:15 ls -ltra
600 2018-10-16 12:34:21 tail run_tophat.out
601 2018-10-16 12:34:24 cat run_tophat.err
602 2018-10-16 12:54:38 history 10
603 2018-10-16 12:56:14 export HISTTIMEFORMAT='%F %T '
604 2018-10-16 12:56:18 history 10
[Link]
131
INPUT AND OUTPUT
132
Redirection
• Every process has three file descriptors (file
handles): STDIN (0), STDOUT (1), STDERR (2)
• Content can be redirected
133
Combine STDOUT and STDERR
Redirect file descriptor 2 from STDERR to wherever file
cmd 2>&1
descriptor 1 is pointing (STDOUT)
• Ordering is important
Correct:
cmd > [Link] 2>&1 Redirect file descriptor 1 from STDOUT to filename
[Link], then redirect file descriptor 2 from STDERR to
wherever file descriptor 1 is pointing ([Link])
Incorrect:
cmd 2>&1 > [Link] Redirect file descriptor 2 from STDERR to wherever file
descriptor 1 is pointing (STDOUT), then redirect file
descriptor 1 from STDOUT to filename [Link]
134
Redirection to a File
• Use better syntax instead – these all do the
same thing:
135
Redirection
• Appending to a file
cmd 1>> [Link] 2>&1 Combine STDOUT and STDERR, append to [Link]
136
Named Pipes/FIFO
• Send STDOUT and/or STDERR into temporary
file for commands that can't accept ordinary
pipes
137
Named Pipes/FIFO
• FIFO special file can simplify this
• You typically need multiple sessions or shells
to use named pipes
138
Named Pipes/FIFO
• Can be used to consolidate output without
appending to a file
$ cat pipe*
139
Process Substitution
• The operators <( ) and >() can be used to
create transient named pipes
• AKA process substitution
$ diff <(ls /home/$USER) <(ls
/home/$USER/.snapshot/Weekly.2018-12-30*)
$ cat /usr/share/dict/words > >(grep zag)
# equivalent to:
#diff <(zcat examples/pipes/[Link] > >(sort) )
<(zcat examples/pipes/[Link] > >(sort) )
141
PIPELINES AND JOBS
142
Pipeline
143
Pipeline
144
examples/pipes/[Link]
input=examples/pipes/genome_stuff.csv
cat <(cut -d',' -f1,2,22-33 $input | head -1 \
| tr ',' $'\t') <(cut -d',' -f1,2,22-33 $input \
| grep chrX | tr ',' $'\t' | sort -k3)
145
Job Control
• A job is another name for pipeline
echo Hello World! > x | cat x | grep o
146
Foreground and Background
• A job (pipeline) runs in the foreground by
default
• Asynchronous jobs are run in background (in
parallel, fire and forget)
sleep 5 &
148
Job Control
• The shell itemizes jobs by number
$ sleep 10 &
[1] 8683
$ sleep 10 &
[2] 8684
$ sleep 10 &
[3] 8686
$ jobs
[1] Running sleep 10 &
[2]- Running sleep 10 &
[3]+ Running sleep 10 &
$
[1] Done sleep 10
[2]- Done sleep 10
[3]+ Done sleep 10
149
Job Control
• A job can be moved from foreground to
background with [CTRL-z] and bg
$ [Link] | [Link] | grep normal
[CTRL-z]
[1]+ Stopped [Link] | [Link] ..
bg
[1]+ [Link] | [Link] ..
• Can be brought back with fg
$ jobs
[1]+ Running [Link] | step2.. &
$ fg
[Link] [Link] ...
150
SUBSHELLS
151
Shells and Subshells
• A shell is defined by a set of variables, options,
and a current working directory (CWD)
• Subshells (child shells) inherit the
environment and CWD
• Changes to the environment and CWD are not
propagated back to the parent
152
Talking To Yourself
$ pwd
/home/user
$ export NUMBER=5
$ bash
$ ((NUMBER++))
$ echo $NUMBER
6 in a subshell
$ cd /scratch
$ exit
$ echo $NUMBER
5
$ pwd
/home/user
153
examples/subshells/[Link]
pwd
for i in {1..4} ; do
(
BASE=/tmp/$i.$RANDOM
mkdir $BASE ; echo -n "OLD DIR: " ; pwd
cd $BASE ; echo -n "NEW DIR: " ; pwd
sleep 2
rmdir $BASE
)
done
pwd
154
examples/subshells/[Link]
(
echo this is running in a subshell
echo exiting now
exit
)
echo intermission
{
echo this is running in the current shell
echo exiting now
exit
}
echo all done!
155
COMMAND LISTS
156
Command List
• Sequence of one or more jobs separated by
‘;’, ‘&’, ‘&&’, or ‘||’.
• Simple commands/pipelines/jobs are run
sequentially when separated by ‘;’
157
Command List
• Sequential command list is equivalent to
echo 1 > x
echo 2 > y
echo 3 > z
• or
date
sleep 5
sleep 5
sleep 5
date
158
Command List
• Asynchronously when separated by ‘&’
159
Command List
• Asynchronous command list is equivalent to
echo 1 > x &
echo 2 > y &
echo 3 > z &
• or
date
sleep 5 &
sleep 5 &
sleep 5 &
wait
date
160
Grouped Command List
• To execute a list of sequential pipelines in the
background, or to pool STDOUT/STDERR,
enclose with ‘()’ or ‘{}’
$ ( cmd 1 < input ; cmd 2 < input ) > output &
[1] 12345
$ { cmd 1 < input ; cmd 2 < input ; } > output &
[2] 12346
161
Grouped Command List
• '{ }' runs in the current shell
• '( )' runs in a child/sub shell
162
Grouped Command List Details
(sleep 3 ; sleep 5 ; sleep 8)
163
Grouped Command List Details
• Grouped command list run in background are
identical to '( )'
(sleep 3 ; sleep 5 ; sleep 8) &
164
Grouped Command List Details
(sleep 3 & sleep 5 & sleep 8 &)
165
examples/parallel/geography_serial.sh
tag=$RANDOM
zcat [Link] > $[Link]
function reformat {
cat <(grep "^$1" $[Link] | sort -nk2) <(echo "--------") >
$[Link]$2
}
reformat "Africa" 1
reformat "Asia" 2
reformat "Europe" 3
reformat "North America" 4
reformat "Oceania" 5
reformat "South America" 6
166
examples/parallel/geography_parallel.sh
tag=$RANDOM
zcat [Link] > $[Link]
function reformat {
cat <(grep "^$1" $[Link] | sort -nk2) <(echo "--------") >
$[Link]$2
}
{
reformat "Africa" 1 &
reformat "Asia" 2 &
reformat "Europe" 3 &
reformat "North America" 4 &
reformat "Oceania" 5 &
reformat "South America" 6 &
}
wait
167
CONDITIONAL STATEMENTS
168
Exit Status
• A process returns an exit status (0-255)
• 0 = success (almost always)
• 1 = general error, 2-255 = specific error
• Stored in $?
$? parameter
cat /var/audit
echo $?
169
Exit Status
• Exit status value is not very helpful
ls /zzz
echo $?
170
test
• test is a general conditional statement
ls ~/.bashrc
/home/user/.bashrc
echo $?
test -e ~/.bashrc
echo $?
171
test
• take action based on results of test
test -f ~/.bashrc && tail -n 1 ~/.bashrc
172
Conditional Statement Run-on
$ ( ( test -e ~/.bashrc && echo "~/.bashrc exists" ) || (
test -e ~/.bash_profile && echo "~/.bash_profile exists" )
|| ( echo "You may not be running bash" ) )
/home/user/.bashrc
173
if .. elif .. else .. fi
if test-commands ; then
consequent-commands
elif more-test-commands ; then
more-consequents
else
alternate-consequents
fi
174
if
if test -e ~/.bashrc
then echo "~/.bashrc exists"
elif test -e ~/.bash_profile
then echo "~/.bash_profile exists"
else echo "You may not be running bash"
fi
~/.bashrc exists
175
examples/conditionals/[Link]
176
[ and [[
• [ is an executable file
which [
/usr/bin/[
• [[ is a builtin
• both substitute for test
[[ -d /tmp ]] && echo "/tmp exists"
177
Conditionals: test and [[ ]]
• test has many different primaries and
operators
help test
178
General if Statements
• if evaluates exit status, so it can be used with
any command
if grep -q bashrc ~/.bash_profile ; then
echo yes
fi
179
General if Statements
• Identical to grouped command list
[[ -e /tmp ]] && echo "/tmp exists"
/tmp exists
not equal
180
Boolean Operators
• Multiple if statements in series
181
Conditional Command List
• A list can execute sequence pipelines
conditionally
• Execute cmd2 if cmd1 was successful
ls ~/.bashrc && tail ~/.bashrc
183
Booleans for Math
• Can use math as conditionals in multiple tests
a=4
if ((a==4)) ; then echo yes ; else echo no ; fi
yes
no
yes
184
Booleans for Math
• Be careful with equal signs!
a=4
echo $a
yes
echo $a
185
PATTERN MATCHING
186
Pattern Matching
• There are three types of matches, standard
glob, extended glob, and extended regular
expression (regex)
• *, ?, [?-?],[^?],[[:CLASS:]] are standard glob
• ?(), *(), +(), @(), !() are extended glob
• +, {N}, (), \, ^…$ are allowed for regex
187
Pattern Matching -- Glob
• * : match any string
• ? : match any single character
• [?-?] : match range of characters
• [!?] or [^?] : not match character
mkdir trash && cd trash
touch {{1..9},{a..z}}
ls [a-e1-4]
1 2 3 4 a b c d e
188
Character Classes
• [[:CLASS:]] can be included with pattern
matching
touch {1..9} y{1..9} z{1..9}
ls [[:alpha:]]4
y4 z4
• full list
alnum cntrl print word
A3
ls *[[:punct:]]*
%5 x.9
$ ls [![:lower:]]*
%5 A3
190
Extended Glob
• Enabled with shopt -s extglob
a=939
[[ $a == +([0-9]) ]] && echo is a number
is a number
191
Extended Glob Matching
• Multiples
touch apple pear fig pineapple plum orange
ls p+([a-z])
ls ?(pine)apple
apple pineapple
ls @(p|f)*([a-z])
192
Pattern Matching Conditionals
• == or != for glob
x=apple
[[ $x == apple ]] && echo this is an apple
[[ $x != pear ]] && echo this is NOT an apple
[[ $x == ?(pine)apple ]] && echo some kind of apple
193
Pattern Matching Conditional
• Test if a string matches a pattern
• Is a variable a number?
a=939
[[ $a == [0-9][0-9][0-9] ]] && echo is a number
is a number
no
194
Regular Expressions
• Allow more precise matching
• Only enabled with =~ operator
x=fig
[[ $x =~ ^f[io]g$ ]] && echo this is probably fig
[[ ! $x =~ ^d[io]g$ ]] && echo huh?
123
195
$BASH_REMATCH
• Can capture a submatch using () and
$BASH_REMATCH array
• examples/matching/[Link]
str="The quick red fox jumped over the lazy brown dog"
is a number
if [[ $str =~ quick\ (.*)\ fox ]] ; then
echo Total match: ${BASH_REMATCH[0]}
echo Submatch: ${BASH_REMATCH[1]}
fi
196
examples/matching/matching_number.sh
197
examples/matching/matching_number2.sh
#!/bin/bash
shopt -s extglob
case $1 in
[0-9][0-9][0-9]) echo three-digit number ;;
*([-\+])+([0-9]) ) echo integer ;;
*([-\+])*([0-9]).+([0-9]) ) echo floating point ;;
*([-\+])*([0-9]).+([0-9])e*([-\+])+([0-9]))
echo scientific notation ;;
*) echo IDK ;;
esac
198
examples/pipes/[Link]
199
case … esac
• Fixed pattern matching, small selection
case word in
pattern )
commands ;;
pattern )
commands ;;
esac
200
examples/conditionals/[Link]
animal=$1
[[ -n $animal ]] || { echo What animal?; exit; }
case $animal in
dog)
echo "this is a dog” ;;
cat)
echo "this is a cat” ;;
fish)
echo "this is a fish” ;;
*)
echo "This is not on my list” ;;
esac
201
LOOPS
202
for .. do .. done
for name in words
do
commands
done
203
Loops - for
• for is used to step through multiple words
for i in apple pear fig ; do echo $i ; done
apple
pear
fig
204
Loops - for
• With brace expansion:
for i in {1..5}; do echo $i ; done
1
2
3
4
5
205
Loops - for
• With arrays
array=(moe larry curly)
for i in "${array[@]}" ; do echo $i ; done
moe
larry
curly
206
Walk Through Directories
• Find all files in /home and count how many
lines are in each file:
for file in $(ls -a ~/); do
[[ -f ~/$file ]] && wc -l ~/$file
done
2 .bash_logout
12 .bash_profile
8 .bashrc
20 .emacs
11 .kshrc
34 .zshrc
207
C-style for loop
• for can be used for integer traversal
for (( i=1 ; i < 1000 ; i=i+i ))
do
echo $i
done
1
2
4
8
16
32
64
128
256
512
208
while .. do .. done
while test-commands
do
consequent-commands
done
209
until .. do .. done
until test-commands
do
consequent-commands
done
210
Loops - until
• Until uses test commands
• Handy with math
a=0
until [[ $a -gt 10 ]] ; do echo $a ; ((a=a+3)) ; done
0
3
6
9
1
2
3
4
5
212
continue
• Can be used to skip to next element
for a in {1..5}; do
if [[ $a == 2 ]]; then
continue;
fi
echo $a
done
1
3
4
5
213
break
• Can be used to end loops or skip sections
a=1
while [[ 1 ]] ; do
echo $a
if (( a > $(date +%s) )) ; then
break
fi
(( a=a+a ))
done
1
2
4
…
2147483648
214
examples/loops/[Link]
iterations=5
iterations_remaining=$iterations
seconds_per_step=2
while (( $iterations_remaining > 0 ))
do
if (( ($(date +%s) % $seconds_per_step) == 0 ))
then
echo -n "$iterations_remaining : "
( date ; sleep 10 ) &
((iterations_remaining--))
fi
sleep 1
done
215
examples/loops/genome_nonsense.sh
#!/bin/bash
BASE=gn.$RANDOM
for i in {1..22} X Y M ; do
label=$i
if [[ $i == [[:digit:]] ]]; then
label=$(printf '%02d' $i)
fi
[[ -f $BASE/$label/[Link] ]] && break
[[ -d $BASE/$label ]] || mkdir -p $BASE/$label
pushd $BASE/$label 2>&1 > /dev/null
echo Running chr${i}_out
# actually do something, not this
touch trial_chr${i}.out
popd >& /dev/null
done
216
ACCESSORIZE
217
Interactive Script Input
• use the read command to interactively get a
line of input:
echo -n "Type in a number: "
read response
echo "You said: $response"
$ bash [Link]
Type in a number:
You said: 4
$
218
Using while and read in a script
• examples/loops/[Link]
while read var
do
if [[ $var == "exit" ]]
then
break
fi
echo $var
# do something else with $var
done
219
Walk a file with read
• examples/loops/repeat_file.sh
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "Text read from file: $line"
done < "$1"
220
examples/options/[Link]
mem="1g"
tmpdir="/tmp"
usage="$0 [-m] [-t] [-h]
221
examples/options/[Link]
#!/bin/bash
$ ./[Link]
Pick a fruit, any fruit
1) apple 3) fig 5) pineapple
2) pear 4) plum 6) orange
#? 4
You picked plum
222
STUPID PET TRICKS
223
Extended Math
• Use bc instead:
number=$(echo "scale=4; 17/7" | bc)
echo $number
2.4285
x=8
y=3
z=$(echo "scale = 3; $x/$y" | bc)
echo $z
2.666
$ echo ${string:7:2}
78
$ echo ${string:7:-2}
7890abcdef
$ echo ${string: -7}
bcdefgh
$ echo ${string: -7:0}
225
Substring expansion with arrays
$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h)
$ echo ${array[@]:7}
7 8 9 0 a b c d e f g h
$ echo ${array[@]:7:2}
7 8
$ echo ${array[@]: -7:2}
b c
$ echo ${array[@]: -7:-2}
bash: -2: substring expression < 0
$ echo ${array[@]:0}
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${array[@]:0:2}
0 1
$ echo ${array[@]: -7:0}
226
Parse fasta file
$ cat [Link]
>gi|bogus
abcde
>gi|nonsense
xyz123
>gi|something else
ABCDEF123
$ array=("${array[@]:1}")
227
grep
• Find only that which matched
ls -l /home | grep -o "Dec .[[:digit:]] ..:.."
• Recursive search
grep -R -l bash *
228
egrep
• Extended grep allows additional
metacharacters like +, ?, |, {} and ()
egrep
'ftp/phase3/data/[^\/]+/exome_alignment/[^\/]+\.mapped\.ILLUMINA\
.bwa\.[^\/]+\.exome\.[^\/]+\.bam'
/fdb/1000genomes/ftp/[Link]
229
find
• Find large files
find . -type f -size +1M
230
find
• Find and update files and directories in a
shared directory
$ find . -user [you] ! -group [grp]
$ find . -user [you] ! -group [grp] -exec chgrp
[yourgroup] {} \;
231
find
• Find newest and oldest files in a directory tree
find . -type f -printf '%Tc %p\n' | sort -nr | head
find . -type f -printf '%Tc %p\n' | sort -nr | tail
232
sort
• input/file_for_sorting.txt
sort input/file_for_sorting.txt
• Multi-column sort
sort -k3 -k1 -k4 input/file_for_sorting.txt
233
sort
• Sort file, locking top line
cat input/file_for_sorting.txt | (read -r; \
printf "%s\n" "$REPLY"; sort -k3 -k1 -k4)
234
sort
• Deal with missing values
cat input/file_for_sorting.txt | (read -r; \
printf "%s\n" "$REPLY"; sort -t $'\t' -k6h)
• man sort
235
Spaces in file names
• Replace newline with null character
for i in $(ls -1) ; do
wc -l $i
done
find . -type f -print0 | xargs -0 wc -l
236
Tab delimited files
• Rearrange order of columns using awk
awk 'BEGIN { FS = "\t" } ; {print $3FS$2FS$1}' \
input/file_for_sorting.txt
237
Use of IFS
• Parse string into words
IFS=: p=($PATH)
for i in ${p[@]}; do echo $i ; done
/usr/bin
/bin
/usr/local/bin
/home/user/bin
238
complete
• Tab-complete possible arguments
function do_something { echo You picked $1; }
array=(pineapple apple pear fig banana)
complete -W "${array[*]}" do_something
$ do_something <tab><tab>
apple banana fig pear pineapple
$ do_something a<tab><tab>
apple
$ do_something p<tab><tab>
pear pineapple
239
complete
• Specify file type allowed
complete -f -X '!*.tsv' do_something
$ do_something input/<tab><tab>
[Link] [Link] [Link] [Link]
[Link]
• man complete
240
hash
• Similar to history table
• Hard-code executable paths outside of $PATH
• Keep a count of executable calls
$ hash
$ hash -l
$ hash -p /path/to/command name
$ hash -d name
$ hash -r
241
readarray
• Read a file into an array
$ cat file_to_be_mapped.txt
This is line one
The second line
Finally line 3
$ readarray zzz < file_to_be_mapped.txt
$ echo ${zzz[1]}
The second line
242
Sort elements of an array
• Use xargs
array=(apple pear fig plum pineapple orange)
echo ${array[@]} | xargs -n 1 | sort | xargs
0 1 2 3 4 5 6 7 8 9
243
Other uses for xargs
• Print wc output neatly
find . -type f -print0 | xargs -0 wc
244
awk and sed
• awk is a scripting language
awk '{sum += $2} END {print sum/NR}' \
input/file_for_sorting.txt
245
Funny Characters
• Windows text editors will add carriage returns
file input/[Link]
246
Funny Characters
• You can find non-printing characters using
sed and grep:
sed 's/\r/\xFF/g' input/[Link]
247
Funny Characters
• Unicode:
LANG=C grep -n --color=always \
'[^[:cntrl:] -~]\+' input/[Link]
• Even tabs:
1:This➤file➤has➤tab delimited➤fields➤for➤searching
248
highlightTabs, highlightUnicode
$ [Link]
examples/funny_characters/tab_delimit.txt
1:This➤file➤has➤tab delimited➤fields➤for➤searching
$ [Link] examples/funny_characters/[Link]
1:This is a file that contains unicode characters
'소녀시대' That snuck in somehow
2:Strange space character: [ ] em space U+2003
4:Another funny character '█'
249
screen and tmux
• Allows login sessions to be saved, detached,
and reattached
• Cryptic controls with [CTRL-a]
$ screen
250
EXTRAS
251
Expanded List of Linux Commands
a2p chmod dos2unix getopts lftp openssl readlink sort tree wc
a2ps chown du ghostscript lftpget passwd readonly source true wget
acroread chsh echo glxinfo ln paste rename split tset whatis
alias cksum egrep gpg local patch renice splitdiff type whereis
apropos clear emacs grep locate pathchk reset sqlite3 ulimit which
at cmp enable groups lockfile pdf2ps resize ssh umask whiptail
awk column enscript gs login perl return stat unalias who
basename combinediff env gunzip logname pgrep rev strace uname whoami
bash comm eval gvim logout php rexec stream unexpand whois
batch continue exec gvimdiff look pico rlogin strings uniq xargs
batchlim cp exit gzip ls pidof rm submitinfo unix2dos xclock
bc crontab expand hash lsof ping rmdir suspend unlink xdiff
bg csh export head mac2unix pinky rsh svn unset xeyes
bind csplit expr help man pkill rsync swarm unzip xterm
break curl factor history man2html popd scp swarmdel updatedb yes
bunzip2 cut false host md5sum pr screen tac uptime zcat
bzcat cvs fg hostname merge printenv script tail urlview zcmp
bzcmp date fgrep iconv mkdir printf sdiff tailf users zdiff
bzdiff dc file id mkfifo ps sed tar usleep zforce
bzgrep dd find info more pushd sendmail tcsh vdir zgrep
bzip2 declare finger interdiff mv pwd seq tee vi zip
bzip2recover df flock iostat namei python set telnet view zipgrep
bzless diff fmt jobcheck nano qdel setsid test vim zipinfo
bzmore diff3 fold jobload netstat qselect sftp time vimdiff zipnote
cal dir free jobs newer qstat sg timeout3 vimtutor zipsplit
cat dircolors freen join newgrp qsub sh times vmstat zless
cd dirname ftp kill nice quota shift top zmore zsh
checkquota dirs funzip ksh nl rcp shopt touch wait
chfn disown gawk less nohup rdist shred tr wall
chgrp display gedit let oclock read sleep trap watch
252
Definitions
• Character: result of
a keystroke character
• Metacharacter:
separates words
metacharacter
• Blank: space, tab,
or newline | & ; ( ) < > [ ] blank
blank
253
Definitions
• Token: one or more token
characters separated
word operator
into fields
• Word: a token with
no unquoted
metacharacters
• Operator: a token
with one or more
metacharacters
254
Definitions
• Name: a word with token
[a..z,A..Z,0..9,_] only
• Control operator: word operator
performs control name
functions control operator
values
word operator
• Variable: name for
name
storing values, must control operator
function/alias
begin with letter || && & ; ;; | |&
( ) newline
• Special parameter: parameter
can’t be modified variable
redirection operator
• Positional special parameter
< << >> >
parameters: for positional parameter
>& <> <&
retrieving arguments filename
reserved word 256
Shell Parameters - Special
257
Bash Variables SET
• $BASH_REMATCH
• $BASH_SUBSHELL
• $PWD
• $REPLY
• $SHLVL
• … type man bash, search for Shell Variables
258
Bash Variables USED
• $BASH_ENV
• $HISTFILE
• $HISTFILESIZE
• $IFS
• $PATH
• … type man bash, search for Shell Variables
259
Questions? Comments?
staff@[Link]
260