Scripting More Shell Scripts Adapted from Practical Unix and Programming Hunter College Copyright 2006 2009 Stewart Weiss
Back to shell scripts Now that you've learned a few commands and can edit files, you can start to write shell scripts. You need a few more tools to make this possible. For starters, you need to know how a shell script can access the words you type on its command line. For example, suppose I want to write a script named swap that when called like this: swap word1 word2 would output this: word2 word1 41 Comp 190 Scripting Languages
Command line arguments Bash can access the words on the command line using the variables $1, $2, $3, and so on. The first word is stored in $1, the second, in $2, etc. The number of words on the line, excluding the command itself, is stored in a variable named $#. Therefore, our swap script would be as simple as #!/bin/bash echo $2 $1 This displays the second word, then the first word 42 Comp 190 Scripting Languages
Adding error-checking: test Scripts should always check that they have the correct number of arguments and that they are all valid. swap just has to check that there are exactly 2 words, so it needs to test whether $# is equal to 2. The test command evaluates an expression. For example test 1 -ne 2 is true because 1 is not equal to 2. test 2 -eq 2 is true because 2 equals 2. The other operators are -le, -lt, -gt, and -ge. Can you guess what these mean? 43 Comp 190 Scripting Languages
Other forms of test If you read the man page for test, you will see that there are other ways to use it. For example [ 1 -ne 2 ] is equivalent to test 1 -ne 2 You can put square brackets around an expression but there must be spaces on either side of them: [1 -ne 2] would be an error. 44 Comp 190 Scripting Languages
Using the if command Every shell has a command named if. In bash, you have to follow a very specific set of rules to use it. It look like if test-command then any sequence of commands fi where the words if, then, and fi are on separate lines. 45 Comp 190 Scripting Languages
Example if command if test $# -ne 2 then echo usage: swap word1 word2 exit fi This piece of shell script will print a usage message if the number of words on the command line is not equal to 2. It will also quit immediately after printing the message, no matter what commands follow the word fi. 46 Comp 190 Scripting Languages
Putting it all together We can put the testing bit of stuff ahead of our echo command to do our input-checking, and we now have a safe script: #!/bin/bash if test $# -ne 2 then echo usage: swap word1 word2 exit fi echo $2 $1 47 Comp 190 Scripting Languages
Another Type of Test The test command has many different types of tests. Many are called file tests and they can be used to test whether a file exists, or is of a given type, or size, or has some other property. For example: #!/bin/bash if test -e $1 then echo $1 exists fi 48 Comp 190 Scripting Languages
Negating Tests There is no test that is true if a file does not exist. If you want to print an error message if the user did not supply a filename, you need to negate the test. The exclamation mark negates expressions: if test! -e myfile is true if myfile does not exist, and is false if it does. If $1 is a command line argument then if test! -e $1 is true if it is not the name of a file that exists. 49 Comp 190 Scripting Languages
Shell comments Add your authorship and other information in a comment (a line that starts with #: #!/bin/bash # Written by Stewart Weiss, 09/24/2009 if test $# -ne 2 then echo usage: swap word1 word2 exit fi echo $2 $1 50 Comp 190 Scripting Languages
Shell comments Add your authorship and other information in a comment (a line that starts with #) #!/bin/bash # Written by John Barr, 09/20/2018 if test $# -ne 2 then echo usage: swap word1 word2 exit fi cat $2 $1 > newfile.txt # Any shell command works! 50 Comp 190 Scripting Languages
Adding comments to the script A line that starts with # and no! after it is called a comment. The shell ignores everything to the right of the #. In fact, the # can be written to the right of a command and the shell will ignore the rest of the line after the #: # Written by Stewart Weiss, 09/24/2009 # This script swaps words. echo $2 $1 # swap first and second words
Arithmetic $((expression)) Must enclose the expression in double quotes #!/bin/bash echo $(( 8#100 )) echo $(( 2#1010 )) i=10 echo $(( i+5 )) # can use spaces in expression but not in = i=$(( i *=5 )) echo $i
More Arithmetic $((expression)) Must enclose the expression in double quotes #!/bin/bash echo $a # spaces optional within paren a=$(( a + 2 )) echo $a b=$(( a < 100 )) # 0 = false, 1 = true echo $b
Loops while command do done command command... # Written by John Barr, 09/20/2018 i=1 # no spaces allowed! No $ necessary while [ $i -le 5 ] do echo $i # this is a command; need $ i=$((i+1)) #aritmetic expression! done
Example: a phonebook The phonebook: Alice Chebba 971-555-2015 Barbara Swingle 201-555-9257 Liz Stachiw 212-555-2398 Susan Goldberg Susan Topple 212-555-4932 201-555-7776 Tony Iannino 973-555-1295 Create this in your account.
Example: a phonebook The lu script: 1 #! /bin/bash 2 grep $1 phonebook Try these: $ lu Alice $ lu Susan $ lu Susan T $ lu "Susan T" Why does the last command still give 2 results?
Example: a phonebook extended The lu script version 2: 1 #! /bin/bash 2 grep "$1" phonebook Try these: $ lu Tony $ lu Susan $ lu Susan T $ lu "Susan T" grep saw "Susan T" as 2 different arguments! What difference do the quotes around $1 make? What do you get now?
Example: a phonebook adding Write a script named "an" to add an entry to the phonebook. Remember that there is a tab between the name and the number! Try these comands: $ an 'Stromboli Pizza' 973-555-9478 $ more phonebook
Example: a phonebook adding The an script version 1: 1 #! /bin/bash 2 echo "$1 $2" >> phonebook Note that there is a tab between the arguments. Try: $ an 'Stromboli Pizza' 973-555-9478 Is the phonebook still sorted?
Example: a phonebook adding The an script version 2: 1 #! /bin/bash 2 echo "$1 $2" >> phonebook 3 sort -o phonebook phonebook what does the -o flag do?
Example: a phonebook removing Write a script named "rem" to add an entry to the phonebook. Remember that there is a tab between the name and the number! Note: do not name your script rm! Why? Try these comands: $ rem 'Stromboli Pizza' $ more phonebook
Example: a phonebook remove The rem script version 1: 1 #! /bin/bash 2 grep -v "$1" phonebook > /tmp/phonebook 3 mv /tmp/phonebook phonebook Try: $ rem "Stromboli Pizza" $ rem Susan What happens with the last command? How would we fix this?
Example: a phonebook remove The rem script version 1: 1 #! /bin/bash 2 grep -v "$1" phonebook > /tmp/phonebook 3 mv /tmp/phonebook phonebook How do we fix this? Must recognize: 1. If there are no matches 2. If there is more than 1 match To find the number of matches: grep -o "$1" phonebook wc -l
Example: a phonebook remove The rem script version 1 How do we fix this? Must recognize: 1. If there are no matches 2. If there is more than 1 match To do find the number of matches: grep -o "$1" phonebook wc -l now must save the number of matches in a variable: lines=$(grep -o "$1" phonebook wc -l)
Example: a phonebook remove The rem script version 1 How do we fix this? Must recognize: 1. If there are no matches 2. If there is more than 1 match Now we just need to test the value in $line See the next 2 slides.
Example: a phonebook remove The rem script version 2: 1 #!/bin/bash Check for the 2 if [ "$#" -ne 1 ] correct number 3 then of arguments 4 echo "Incorrect number of arguments." 5 echo "Usage: rem name" 6 exit 1 7 fi 8 9 lines=$(grep -o "$1" phonebook wc -l) 10 Line numbers are part of the editor, not the code!
Example: a phonebook remove The rem script version 2 (cont): 11 if [ $lines -eq 0 ] 12 then 13 echo "no match for " $1 14 exit 1 15 elif [ $lines -gt 1 ] 16 then 17 echo "Too many matches" 18 grep "$1" phonebook 19 exit 1 20 else 21 grep -v "$1" phonebook > \tmp\phonebook 22 mv \tmp\phonebook phonebook 23 fi
Things to try Try creating a few simple scripts of your own. It will give you practice using gedit if you are at a UNIX console, or vi or nano if you are not. Read about the test command and learn its tricky syntax. Play around with > to store the output of various commands. 52 Comp 190 Scripting Languages