More Scripting 1 • Output with printf • Input ◦ from a file ◦ from a command arguments ◦ from the command read 2 • A script can test whether or not standard input is a terminal [ -t 0 ] • What about standard output, and standard error? (hint, 0, 1, 2) • For example, if we redirect the output of one command into our script , then stdin is not a terminal 3 • Occasionally you'll see a command called, : • The command is actually colon, ":" • : arguments • That command expands its arguments and does nothing with them, resulting in a 0 exit status 4 • when you finish a script, you need to run it to verify correct operation • you're expecting certain things from your script on certain runs ◦ example: it expects arguments and you supply none – it should print an error message ◦ example: you supply the wrong number of arguments – it should print an error message • run your script with good input, and bad ◦ check that operation is correct for good and bad ◦ testing should "cover" all lines of code: every line of the script runs at least once during all your testing 5 • test your script incrementally as you build it up into its final form • you need to be able to determine whether your script is behaving as you intended • use –x and/or –v to "watch" it execute: ◦ sh –x –u myscript.sh ◦ -x: print each statement before executing 6 • http://teaching.idallen.com/cst8207/14w/notes/320_shell_variables.html • http://teaching.idallen.com/cst8207/14w/notes/440_quotes.html • You want variables to be inside double quotes, for three main reasons: 1. globbing characters inside the variable will not be used to match filenames when double qoutes are used 2. if the variable is empty, without double quotes it vanishes completely, and that's normally not what we want 3. Spaces inside the variable will not split the value into words if double quotes surround the variable 7 • If a variable has a null value, as in myvar= # both of the following result in an error, because myvar is empty if [ $myvar = something ] ; then echo yes; fi # after variable expansion the above becomes (error) if [ = something ] ; then echo yes; fi • If we put the same variable in double quotes: myvar= # both of the following do not result in an error (or any output) if [ "$myvar" = something ] ; then echo yes ; fi # after variable expansion the above becomes same as if [ "" = something ] ; then echo yes ; fi 8 • formatted printing (man printf) • printf format arguments [...] ◦ format is a string of characters containing ‧ plain characters: copied straight to output ‧ escape sequences: ‧ \n : newline ‧ \t : tab ‧ \a : bell (try it!) ‧ format specifications with three parts ‧ flag ‧ width ‧ precision 9 • flags: ◦ -: left justify rather than right justify ◦ +: always display the sign of a number ◦ : minus sign if negative, nothing if positive ◦ 0: pad with 0's instead of spaces • width: ◦ if the output has fewer than width characters, pad it with spaces on the left (see flags above) so it occupies width characters • precision: ◦ an optional dot and digit string specifying the maximum number of characters (or number of digits after the decimal point for 'e' and 'f' –see below) 10 • format: a character specifying the format of the output ◦ d: decimal integer ◦ f: floating point number ◦ s: string (if precision is 0 or missing, all characters are printed, otherwise limited by precision) 11 printf "hello\tthere" ◦ \t gets replaced with tab printf "hello %s there" you ◦ prints "hello you there" printf "hello %10s there" you ◦ prints "hello you there" • See the file "printf_examples.txt" for more examples 12 Functions in bash • You will learn that functions are exceptionally useful, and it's good to see them in bash. • A function is a group of regular shell-script statements is a self-contained package. • You define a function as: function somename () { statement statement … } • And you call it by using the name as if it were a normal command. 13 bash Functions In general: [ function ] name () compound-command [redirection] Any parameters you pass to a function will be positional parameters inside that function 14 Functions • Function scope is from the point the function is defined to the end of the file (that is, it must be defined before you can use it). Generally, that means that all functions precede the main body of the script. • As a result, previously-written functions are often included in a script using the source (also . (dot)) statement near the top of a script. • You can define local variables to be used only inside the function, while your normal variables from outside the function can always be used. • If you wish, you can pass arguments into a function as positional parameters ($1 and so on; this is by far the recommended approach). 15 Functions • You may have noticed that traps behave like a special form of function. They are called (or invoked) by an event and consist of a collection of command statements. This is not an accident. • To unset (delete or remove) a function: unset -f functionname • To list defined function names (note: my system seems to have over 400 functions, of which I have only defined 4 of my own): declare -F | less • To list functions and definitions: declare -f [functionname] 16 A Simple Sample The rot13 script is an implementation of the Caesar code message encryption. It simply rotates the message 13 characters through the alphabet, retaining case. No numbers or punctuation characters are affected. rot13 () { echo "$*" | \ tr '[a-mA-Mn-zN-Z]' '[n-zN-Za-mA-M]' return 0 } As you can see, rot13 accepts command-line arguments which it passes via echo through a translate (tr) command that will print the result on stdout. Entering rot13 sheesh produces furrfu on stdout, while the reversed rot13 fuurfu displays sheesh. 17 When to write a function There are a lot of scripting situations where writing a short function of your own is a good idea. Some of these include: • Some common activity that will be used frequently • Part of a larger script that will be repeated at least 2 or 3 times, perhaps slightly differently each time • An uncommon activity used only once in a while, but you don't want to have to remember the details • A tricky bit of logic – write once, use over and over, even if its not often • A part of a large script that will only be used once • The "Lego block" approach to scripting – develop functions that can be "plugged together" to form a complete script with a little "glue" 18