Introduction to shell scripting

advertisement
Introduction to shell scripting
Andreas Buzh Skau
buzh@usit.uio.no
Research Computing Services
Slides: http://folk.uio.no/buzh/bash
RCS Course Week Fall 2015
Outline
◮
What is shell scripting ?
◮
How to run the scripts
◮
Variables
◮
Control flow (tests, if-then-else-fi, loops)
Poll
◮
Who has already
◮
used a shell?
Poll
◮
Who has already
◮
◮
used a shell?
written a shell script?
Poll
◮
Who has already
◮
◮
◮
used a shell?
written a shell script?
written a script (R, MATLAB, . . . )?
Poll
◮
Who has already
◮
◮
◮
◮
used a shell?
written a shell script?
written a script (R, MATLAB, . . . )?
written a program (C/C++, Fortran, Java, . . . )?
What is a shell?
◮
The shell is a computer program that presents you with a
command line interface.
◮
You type in a command or set of commands, hit enter and
the shell does what you ask
◮
A supplement or alternative to a Graphical User Interface
(GUI)
⇒ The shell is made for human interaction with computers
What is a script?
◮
A script is a list of commands that the shell will execute in
order.
◮
It’s kept in a text file, rather than being a single line on the
command prompt
◮
Think of it like the script to a movie or play. You are a
director giving a script to the actor.
◮
The actor reads, interprets and executes the script
according to the director’s instructions.
⇒ The shell does the same with your scripts.
Why shell scripting?
◮
A way to store, edit & execute shell commands
◮
◮
◮
◮
store ⇒ avoid repetitive work
adapt ⇒ easily change commands
logic ⇒ gather information and act accordingly
automate ⇒ computers are here to work for you
⇒ Simplifies the repetition of long & complex command
sequences.
What is shell scripting used for?1
◮
A wrapper for a program
SLURM job scripts are shell scripts
Start a program with the same options over and over, easily
◮ Prepare job input data, run job, check results, copy results
⇒ Save time by automating
◮
◮
◮
To manage research environment
Create data/jobs layout (e.g., for parameter studies)
Perform post-processing of results
◮ Document exactly what you did
⇒ May help in reproducing results if necessary.
◮
◮
1
on Abel
Example script: simple.sh
◮
use any (ASCII) text editor: vim, emacs, nano, gedit, . . .
#!/bin/bash
# An example script for the RCS course week
WHO="All"
if [ $# -gt 0 ]
then
WHO="$1"
fi
DATE=$(date)
echo "Welcome to the tutorial, $WHO"
echo "$DATE"
Simple script: How to run it
> bash simple.sh
Welcome ’All’ to RCS Course Week
Oct 27 12:50:23 CET 2015
> bash simple.sh Abel
Welcome ’Abel’ to RCS Course Week
Oct 27 12:50:23 CET 2015
◮
Run script without bash ...?
> ./simple.sh
-bash: simple.sh: Permission denied
◮
Check
> ls -l simple.sh
-rw-r--r-- 1 buzh users 117 Oct 22 18:04 simple.sh
◮
Fix
> chmod u+x simple.sh
> ls -l simple.sh
-rwxr--r-- 1 buzh users 117 Oct 22 18:04 simple.sh
Invocation – Put it in the PATH
◮
How about saving two more keystrokes?
> simple.sh
-bash: simple.sh: command not found
◮
Check
> which simple.sh
/usr/bin/which: no simple.sh in (/hpc/bin:...
which searches the directories in the environment variable PATH
> PATH=$PATH:$HOME/scripts
> simple.sh
Welcome ’All’ to RCS Course Week
Oct 27 12:50:23 CET 2015
◮
Alternative: use absolute path, i.e., /path/simple.sh
Hashbang 2
#!/bin/bash
◮
1st line in each shell script
◮
Lets the OS know which interpreter to use for a script
◮
Not mandatory, but recommended
◮
Different shells have different syntax (sh, ksh, tcsh, zsh etc)
◮
Also works for some other languages, like Perl, PHP etc
2
# is the hash, and ! is the bang. Remnants from the printing industry
Comments
◮
Anything preceded by a # (hash) is ignored by the shell
◮
We call this a ”comment”
◮
The hashbang is a special comment
◮
If you wish to disable part of your script temporarily, just
comment it out
# echo "Velkommen til ITF kurs-uke!
echo "Welcome to the RCS course week!"
Arguments – Welcome ’everybody’
◮
Passing arguments
> arguments.sh everybody
Welcome ’everybody’ to RCS Course Week
◮
Simplified script
echo "Welcome ’$1’ to RCS Course Week"
◮
$1 is a positional parameter
◮
◮
positional parameters are set when the shell is invoked
set with everybody in the invocation above
Arguments – Welcome everybody
◮
Passing multiple arguments
> argumentsX.sh Alice Bob
Welcome ’Alice’ (1) to DRC Course Week
Welcome ’Bob’ (2) to DRC Course Week
Welcome ’’ (3) to DRC Course Week
◮
Enhanced script
#!/bin/bash
echo "Welcome ’$1’ (1) to RCS Course Week"
echo "Welcome ’$2’ (2) to RCS Course Week"
echo "Welcome ’$3’ (3) to RCS Course Week"
◮
$n is a positional parameter
◮
unused positional parameters are empty
Variables
◮
Assignment
VARIABLENAME="any string you like"
◮
◮
◮
◮
VARIABLENAME is of characters a-z, A-Z, 0-9, _, . . .
No space between VARIABLENAME and = and value
Quoting (" or ’) needed if value contains spaces
Usage
$VARIABLENAME
◮
◮
no need to declare before use (default: empty string)
Before the shell executes a line, it will expand
$VARIABLENAME to the actual value contained within.
◮
Note the difference (with/out $)
◮
Untyped (no difference between numbers, text etc)
Variables – Examples
◮
Script
#!/bin/bash
ABEL=Abel
ABLE="Abel is
echo "Welcome
echo "Welcome
echo "Welcome
◮
able"
’$ABEL’ (ABEL) to DRC Course Week"
’$ABLE’ (ABLE) to DRC Course Week"
’$UNSET’ (UNSET) to DRC Course Week"
Output
Welcome ’Abel’ (ABEL) to DRC Course Week
Welcome ’Abel is able’ (ABLE) to DRC Course Week
Welcome ’’ (UNSET) to DRC Course Week
◮
Experiment with quoting
◮
◮
remove double quotes in assignment of ABLE
remove single and/or double quotes in echo for UNSET
Variables – Examples (2)
◮
Variables
mypath=/tmp/scripting_course
myfilename=magic_script.sh
myfile=$mypath/$myfilename
mytext="Welcome !"
mynumber=99
myarray=(apple banana strawberry)
◮
Use
mkdir -p $mypath
echo "$mytext" > $myfile
echo $mynumber >> $myfile
mv $myfile $myfile.${myarray[2]}
for ((i=0; i<=$mynumber; i++)); do echo $i; done
Status
◮
You should now understand the highlighted parts.
#!/bin/bash
WHO=All
if [ $# -gt 0 ]
then
WHO=$1
fi
DATE=$(date)
echo "Welcome ’$WHO’ to RCS Course Week
echo "$DATE"
Variables – Command substitution
◮
The ”date” commands returns the date. We could
timestamp our output like this:
#!/bin/bash
echo -n "Work start at "; date
sleep 3 # Placeholder for actual work
echo -n "Work finished at "; date
Work start at Thu Apr 16 14:28:33 CEST 2015
Work finished at Thu Apr 16 14:28:36 CEST 2015
◮
But what if we wanted to save the date ouput for later use?
Variables – Command substitution(2)
◮
Syntax
VARIABLENAME=$(command with arguments)
◮
Variable is substituted with the command’s output.
#!/bin/bash
START=$(date)
sleep 3 # Placeholder for actual work
STOP=$(date)
echo "Work started at $START"
echo "Work finished at $STOP"
Work started at Thu Apr 16 14:48:49 CEST 2015
Work ended at Thu Apr 16 14:48:52 CEST 2015
◮
Put any command output into a variable!
Control flow
◮
Automate decision making
◮
Adapt to different conditions
◮
Scripts are more than a list of sequential commands
If-then-else – Syntax
if condition
then
some_commands
else
some_other_commands
fi
◮
else branch is optional
◮
condition can be any command!
A quick note about exit codes
◮
All commands in Linux/unix return an exit code
◮
A command that finishes succesfully returns 0
◮
Any non-zero exit code indicates failure
◮
The exit code of the previous command is stored in the
special variable $?
⇒ ”if” responds to the exit code of the condition
If-then-else – Example
◮
Example
#!/bin/bash
CARROTS=10
HORSES=8
if test $CARROTS -ge $HORSES
then
echo "There are enough carrots"
else
echo "Warning: Not enough carrots!"
SADHORSES=$(expr $HORSES - $CARROTS)
echo $SADHORSES will not get a carrot.
fi
There are enough carrots
test – It’s a command called test
◮
For details see man test
◮
Examples
expression
evaluates to true if
EXP1 -a EXP2 both EXP1/2 are true
EXP1 -o EXP2 either EXP1/2 is true
INT1 -eq INT2 integers are equal
INT1 -ge INT2 INT1 ≥ INT2
-e FILE FILE exists
◮ Square brackets in bash is an alias for ’test’
◮
Can improve readability
if [ $CARROTS -ge $HORSES ]
Subshells
◮
Multiple commands can be grouped together within
parenthesis.
if (command; othercommand && ... )
then
echo "Success!"
fi
◮
Run any number of commands, but make sure you
understand the final exit status
Subshells - Final exit status
if (ls /TMP; ls /tmp)
then
echo "Success!"
fi
◮
The last command returns 0, so it’s a success, despite the
first command failing
if (ls /TMP && ls /tmp)
then
echo "Success!"
fi
◮
This would NOT return ”Success!”
Subshells - Using the output
echo $(date)
DATE=$(date)
echo $DATE
◮
Preceding a (subshell) with a $ will return the output of the
executed command
Loops
◮
Loops can do the same thing over and over
◮
Two main types of loops: ”for” and ”while”
(for) – loop syntax
for VAR in LIST
do
work goes here
done
◮
VAR is set to the first item of the list, then the work is done.
(no $)
◮
LIST can be given like ”apple cherry kiwi” or as output of a
program. E.g. $(cat fruits.txt)
◮
Once the work is done for the first item, VAR is set to the
next item in LIST and so on, until LIST is empty
Loops – Example
for NAME in Alice Bob Cindy Dave Erica Frank
do
echo "Hello $NAME"
done
for NAME in $(cat names.txt)
do
echo "Hello $NAME"
done
(While) – loops
#!/bin/bash
i=1
while (( i <= 10 ))
do
echo "I can count to $i"
i=$(($i+1))
done
◮
While loops start only if the expression is true, but continue
until it becomes false
Become a shell scripting user/expert
◮
Read man pages: man bash, man test
◮
Advanced Bash-Scripting Guide:
http://www.tldp.org/LDP/abs/html/
◮
Learn to use cmdline tools like grep, awk, sed, ...
◮
Study examples
◮
Online search
◮
Most important! Practice, practice, practice.
Happy scripting
◮
Course by Andreas Buzh Skau
◮
buzh@usit.uio.no
◮
Slides: http://folk.uio.no/buzh/bash/
Tools, tips and tricks
◮
Debug output
[buzh@stridselg ˜]$ cat debug.sh
#!/bin/bash
cd /tmp
if [ -f test ]; then
ls -l test
else
echo Nope
fi
[buzh@stridselg ˜]$ bash debug.sh
Nope
[buzh@stridselg ˜]$ bash -x debug.sh
+ cd /tmp
+ ’[’ -f test ’]’
+ echo Nope
Nope
◮
Common pitfall: Invisible characters
[buzh@stridselg test]$ cat invisible.sh
one=1
two=2
e c h o o n e plus two equals $(( $one + $two ))
[buzh@stridselg test]$ cat -v invisible.sh
one=1
two=2
echoM-BM- one plus two equals $(( $one + $two ))
◮
This script would give an error: ”command not found”
◮
The reason is that the character between ”echo” and ”one”
is not a space, even though it looks like it
◮
This particular one comes from accidental Alt-Space
instead of Space
◮
’cat -v’ displays non-printing characters in files
◮
Search text with ”grep”
$ cat debug.sh | grep test
echo test
$ grep test debug.sh
echo test
$ grep -c test debug.sh
1
◮
’grep’ is purpose built to search text. Very powerful!
◮
’man grep’ has all the options, but can be daunting.
◮
Display part of a string with ’cut’
$ grep nobody /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/
$ grep nobody /etc/passwd | cut -d: -f5
Nobody
Anonymous NFS User
◮
-d declares the delimiter, -f the field
◮
If you have advanced needs, look at ’awk’ instead
◮
Change text with sed
$ grep nobody /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/
$ grep nobody /etc/passwd | sed ’s/x/y/g’
nobody:y:99:99:Nobody:/:/sbin/nologin
nfsnobody:y:65534:65534:Anonymous NFS User:/var/
◮
The command above is ”swap x with y for all lines”
◮
Forward slashes delimit the components of the command
◮
Powerful: Whole books have been written about it
The end!
Download