1 / 33

CPS 393 Introduction to Unix and C

CPS 393 Introduction to Unix and C. START OF WEEK 5 (UNIX). 9/25/2014. Course material created by D. Woit. 1. Testing & Debugging Shell Pgms. use shell parameters -x or -v to debug interactively bash -v pgm displays every line of pgm just before executing it

trynt
Download Presentation

CPS 393 Introduction to Unix and C

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CPS 393Introduction to Unix and C START OF WEEK 5 (UNIX) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 1

  2. Testing & Debugging Shell Pgms • use shell parameters -x or -v to debug interactively • bash -v pgm • displays every line of pgm just before executing it • bash -x pgm • like -v but substitutes values of variables in each • Before we proceed let us recall: • `command(s)` means that command(s) will be executed in a sub-shell and resulting value will be put in place of command(s) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 2

  3. Testing cont. 9/25/2014 Example: #!/bin/bash #Source: findtrunc truncates input to 8 characters & #looks it up in file gfile # a msg is printed to indicate if found/not found # use first method on linux, second on unix (why? bug in linux bash-- # the read variable only valid within a subshell # that runs each part of a pipe in a different process, so vars do not # get into the process running the "read“ # third method always works, but no help if want to use read to separate #by whitespace # fourth method is valid on both linux/unix is to put a ( before the read # and a ) at the end of the program to keep everything IN the subshell 9/25/2014 Course material created by D. Woit Course material created by D. Woit 3 3

  4. Testing cont. code for findtrunc 9/25/2014 #first method: echo "$1" | cut -c1-8 >tmp read trunc <tmp #second method: echo "$1" | cut -c1-8 | read trunc #third method trunc=`echo "$1" | cut -c1-8` #no spaces between trunc and = if [ "`grep $trunc gfile`" ] then echo Found else echo not found fi 9/25/2014 Course material created by D. Woit Course material created by D. Woit 4 4

  5. Testing continued, code for findtrunc 9/25/2014 • try to run: findtrunc abcdefghijkl • prints Found #if abcdefgh in gfile • try to run: findtrunc • no output, just hangs there , then press ^C , ^D to stop it • prints not found • What's the problem with findtrunc? Why does it hang? • Use -x to find out why: 9/25/2014 Course material created by D. Woit Course material created by D. Woit 5 5

  6. Testing continued, code for findtrunc 9/25/2014 bash -x findtrunc + echo '' + cut -c1-8 + read trunc ++ grep gfile <---- hangs, wanting to grep string gfile from stdin. If we type ^D signals end of stdin, giving... +'[' '' ']' <---- since grep printed nothing on stdout + echo not found <---- since [ ] (null string) is considered false not found + test -e tmp + rm tmp <---- terminates 9/25/2014 Course material created by D. Woit Course material created by D. Woit 6 6

  7. Testing continued, code for findtrunc 9/25/2014 • with bash –ecan tell where hanging • In this case, we forgot the argument to findtrunc, so it was null • we can fix this by adding an : • enclosing if [ $1 ] (if $1 not null) • or something similar, such as if [ $# -ge 1 ] • Note: Could have used ( ) to solve problem of reading from pipe in above program, as in: • echo "$1" | cut -c1-8 | ( read trunc • if [ "`grep $trunc gfile`" ] • then echo Found • else echo not found • fi • ) • Recall ( commands ) means that they will be executed in sub-shell Course material created by D. Woit Course material created by D. Woit 7 7 9/25/2014

  8. Shift 9/25/2014 Shift command is used in while loops to process arguments #!/bin/bash #Source: shiftex #pgm to print its args. while [ "$1" ] #<--- stops when $1= "" (null) do echo $1 shift #<--- moves $2 to $1, $3 to $2 etc. done exit 0 9/25/2014 Course material created by D. Woit Course material created by D. Woit 8 8

  9. Xargs 9/25/2014 • usedto perform cmd repetitively on a group of things from stdin but can be used after redirection • find . -name "*" | xargs grep bash • #prints LINES in files * that contain the string bash • find . -type d -empty | xargs rmdir • #remove empty directories from tree rooted in current dir • ls | xargs -I{} cp {} {}.bak • makes backup copy of all files in current dir. (no spaces between {} please) • if xx is a dir get cp xx xx.bak -- error, but will just print msg for each dir and continue on with files • e.g., what does this print on stdout? • (echo a b c ; echo d e ; echo f) | xargs -I{} echo :{}: 9/25/2014 Course material created by D. Woit Course material created by D. Woit 9 9

  10. HMWK 9/25/2014 1. write a shell program called clean that removes all files called "core" from your directory structure, and also removes all files that have size 0 (0 bytes) from your dir structure. That's your WHOLE dir structure, not just the current dir. (note: "find" can find files that are zero bytes long) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 10 10

  11. HMWK 9/25/2014 • 1.write a shell program called avgs which will read lines from • stdin such as the following (where the dots indicate more lines • of the same kind: • SID LNAME I T1/20 T2/30 • 92876035 WANG S 15 26 • 95908659 CHIANG R 10 29 • . . . . . . . . . . • 91234987 MYRTH R 15 16 • Your shell program will print out a line such as: • Average of T1/20 is 17 and of T2/30 is 24 • where 17 and 24 are the averages of the last 2 columns respectively. Note that your program must keep a total and count for each of the last 2 columns, and must not include data from the first line in the totals and counts. 9/25/2014 Course material created by D. Woit Course material created by D. Woit 11 11

  12. HMWK 9/25/2014 • 2. Modify script avgs so that the "title" line, e.g., • SID LNAME I T1/20 T2/30 above, could be located at ANY LINE of stdin (ie., not necessarily the FIRST line, as above.) • 3. Modify avgs so that the highest and lowest marks are printed for each of T1 and T2, as well as averages. • Your program should produce output such as the following: • T1/20: Average: 17 Hightest: 19 Lowest: 1 • T2/30: Average: 24 Hightest: 29 Lowest: 9 9/25/2014 Course material created by D. Woit Course material created by D. Woit 12 12

  13. HMWK 9/25/2014 4. Modify avgs so that the output above is in PERCENT, e.g., T1/20: Average: 85% Hightest: 95% Lowest: 5% T2/30: Average: 80% Hightest: 96% Lowest: 3% If variable x contains "T1/20" you could use an echo piped to a cut, and assign the result to another variable, or you could use ${x#*/} which will match pattern "*/" against the beginning of the contents of x, delete the shortest part that matches, and return the rest. Thus typeset -i y=${x#*/} would assign 20 to y. Note that pattern */ means anything followed by a "/" 9/25/2014 Course material created by D. Woit Course material created by D. Woit 13 13

  14. HMWK 9/25/2014 5. Write a shell program called findext which will list directories under a given path that contain files/dirs having the given extensions. Program findext takes at least 2 command line arguments. Its usage is: findext path ext1 ext2 ... where "path" is the path to the start of the directory structure you wish to search, and ext1, ext2, etc are extensions. Program findext will print out the directories under path which contain files/dirs that end in .ext1 .ext2 etc Your program does not need to work properly if the user passes glob constructs or special chars as arguments. For example: findext /home/dwoit/courses c scm will list all directories under /home/dwoit/courses that contain files/dirs named *.c and/or *.scm 9/25/2014 Course material created by D. Woit Course material created by D. Woit 14 14

  15. HMWK 5 cont. 9/25/2014 If findext is sent less than 2 command line args, it should print on stderr Usage: findext path arg1 arg2 and exit with exitcode 1 (the word findext above should be printed using $0) If it is passed 2 or more arguments, it should print a list of dirs in which files/dirs of the form *.ext1 *.ext2 etc reside. Then it should exit with exitcode 0. Note that only the DIRECTORY names are printed. Therefore you will have to chop off the trailing file/dir name (the part after the last "/") You can do this with ${var%/*} which says to match pattern "/*" (slash followed by anything) at the END of variable var; and delete the shortest part that matches and return the rest. You will also find utilities sort and uniq useful. 9/25/2014 Course material created by D. Woit Course material created by D. Woit 15 15

  16. Built in commands 9/25/2014 • We saw already: echo, exit, pwd, shopt, break, cd, set, test, read, typeset, etc. • Some others : eval • v1="cmd1 | cmd2" #make a string "cmd1 | cmd2" • v2="cmd3 | cmd4" #make a string • eval "$v1 | cmd5 | $v2" #is really: • cmd1 | cmd2 | cmd5 | cmd3 | cmd 4 #pipes • However if we typed: • $v1 | cmd5 | $v2 • # error: the "|" in v1 not interpreted as pipe 9/25/2014 Course material created by D. Woit Course material created by D. Woit 16 16

  17. Eval cont. 9/25/2014 • Example for eval: • v1="cat table | grep 2" • v2="grep 0 | more " • $v1 | $v2 #some errors like: • grep: |: No such file or directory • grep: more: No such file or directory • Correct invocation is: eval “$v1 | $v2” • Output is: 9 10 11 12 • eval has 2 passes: • 1) makes substitutions • 2) result evaluated i.e, meta chars etc. interpreted properly 9/25/2014 Course material created by D. Woit Course material created by D. Woit 17 17

  18. Eval example 9/25/2014 • #!/bin/bash • #Source: printXth • #Expects a bunch of command line arguments. • #Prompts user and reads an integer (call it X) • #then it prints the Xth command line argument • echo -n "enter an integer: " • read X • the_arg='$'${X} • eval echo "command line arg number ${X} is: ${the_arg}" • echo "command line arg number ${X} is: ${the_arg}" • #note the diff 9/25/2014 Course material created by D. Woit Course material created by D. Woit 18 18

  19. Eval example 9/25/2014 #!/bin/bash #Source: for11 #one way to make command line arg "abc de" work: typeset -i i=1 while [ $i -le $# ] do a='$'$i eval "echo $a" # or b=`eval "echo $a"` ; echo $b #see for12 i=i+1 done 9/25/2014 Course material created by D. Woit Course material created by D. Woit 19 19

  20. HMWK 9/25/2014 Use eval to write a shell program called revargs which will print out its command line args in reverse order. Write a shell program that doesn't use eval to print its clas in reverse order. 9/25/2014 Course material created by D. Woit Course material created by D. Woit 20 20

  21. Shell commands 9/25/2014 most shell cmds (i.e. not built in ones) in "bins" /bin, /usr/bin , /usr/local/bin , even ~/bin shell searches directories to find cmds. searches those in "PATH" to see path echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/courses/bin/i686:: to add (or change) default path, reset PATH in .profile PATH=${PATH}:${HOME}/bin export PATH - Adds /home/dwoit/bin to end of current path (for me) (I put all shell my personal pgms in /home/dwoit/bin) -export makes PATH global (so all subsequent processes can use it.) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 21 21

  22. Problem with path 9/25/2014 • Problem occurs if we have two different commands with same name, • Shell will execute first one it finds in path • i.e. if you wrote a "rm" cmd to use instead of /bin/rm • you must put your bin /dwoit/bin before /bin in PATH, or /bin/rm will be always executed. • (or can make it a function or alias, which are always done first) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 22 22

  23. Functions 9/25/2014 Can use functions to modularize shell programs Can also use them in shell as you use any shell program Often placed in a .profile Syntax: function_name ( ) { command_list; } For example: if we are tired of doing "ls -ld" so make a function called ll ll () { ls -ld } Can also enter interactively in shell: /home/dwoit> ll () { Linux> ls -ld Linux> } 9/25/2014 Course material created by D. Woit Course material created by D. Woit 23 23

  24. Arguments for functions 9/25/2014 Just like for shell programs: $1 $2, ... $* etc Functions in shell programs In a shell program called xy #!/bin/bash #Source: xy abc () { echo "in function abc. My \$2 is: $2" } echo in xy...calling abc x "y z" w abc x "y z" w echo in xy...calling abc a b c d abc a b c d 9/25/2014 Course material created by D. Woit Course material created by D. Woit 24 24

  25. Like complex "alias" 9/25/2014 Functions are done before shell commands Thus, to make "vi" different make a function (in .profile) vi () { for i # each parameter to vi which can file or options +- do x=`echo $i | cut -c1` if [ "$x" != "-" -a "$x" != "+" ] then cp $i $i.bak fi done /usr/bin/vi "$@“ # “$@” is equivalent to “$1” “$2” … } 9/25/2014 Course material created by D. Woit Course material created by D. Woit 25 25

  26. Functions cont. 9/25/2014 • To define "ls" to always be "ls -l" could do alias, or • ls () { • /usr/bin/ls -l • } • But this ls always shows whole contents of the directory. • There is no option to show only selected files and/or directories • Also NOTE1: do not do: • ls () { • ls -l • } • Why? It is a *recursive* call to the newly-defined ls *function* • (Infinite loop) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 26 26

  27. Functions cont. 9/25/2014 NOTE2: in ls() function above we should really do: /usr/bin/ls -l${1+"$@"} instead of: /usr/bin/ls -l Why? the latter ALWAYS does "ls -l" even if you supply arguments e.g., ls x y z will NOT do ls -l ONLY for x y z, it does it for *all* files The ${1+"$@"} means: if $1 is unset or null replace ${1+"$@"} with null; otherwise replace ${1+"$@"} with the expansion of $@ (which are all the function's args) 9/25/2014 Course material created by D. Woit Course material created by D. Woit 27 27

  28. type function_name e.g. once we defined ll() /home/dwoit> type ll ll is a function ll () { ls -ld } /home/dwoit> unset ll /home/dwoit> type ll -bash: type: ll: not found for previous example ls /home/dwoit> type ls ls is a function ls () { /bin/ls ${1+"$@"} } /home/dwoit> unset ls /home/dwoit> type ls ls is hashed (/bin/ls) Determining if something is a function or not 9/25/2014 9/25/2014 Course material created by D. Woit Course material created by D. Woit 28 28

  29. Determining what functions are defined 9/25/2014 typeset -f #lists all functions defined this session << Deleting a function >> unset -f function_name #unset f unsets *variable* f, not function f #however, if no variable defined then unset f will unset function f << Functionscope>> Functions executed in current shell, not subshell (as normal shell pgm) Thus: if function changes variables, current dir, etc – change of variables is PERMANENT 9/25/2014 Course material created by D. Woit Course material created by D. Woit 29 29

  30. e.g. /home/dwoit> ff () { > x="def" > } /home/dwoit> x="abc";echo $x abc /home/dwoit> ff /home/dwoit> echo $x def From a shell program: e.g., #!/bin/bash ff () { x="def" } x="abc" ff echo $x #will print def Function Scope 9/25/2014 9/25/2014 Course material created by D. Woit Course material created by D. Woit 30 30

  31. Variables in a function 9/25/2014 • We can make LOCAL variables in a function by using typeset: • typeset x=30 • makes x local to the function. • Otherwise x is set permanently in current shell 9/25/2014 Course material created by D. Woit Course material created by D. Woit 31 31

  32. Getting at a shell function's positional parameters from within a function it calls: 9/25/2014 • A shell program has parameters $1 $2 ... • If it calls a function, then WITHIN the function, params. $1 $2 ... are those of the function • (the shell program's original $1 $2 ... are not available within the function, but they are still available to the shell program after the function returns) • Even if the shell program calls the function with no arguments, the shell program's params. $1 $2 ... are still unavailable in the function (because they're all null within the function.) • If we need to access shell pgm's args from within a function: • Then store $1, $2, ... in arguments before calling function 9/25/2014 Course material created by D. Woit Course material created by D. Woit 32 32

  33. Passing the shell program’s args to function: 9/25/2014 #!/bin/bash #source: floc #try running this as: floc a b c ff () { echo "in ff: my \$2 is: $2" echo "in ff: my caller's \$2 is ${A[2]}" } echo in floc before ff: \$2 is: $2 A=($0 $*) #initialize an array A to be all the positional params ff xxx yyy zzz echo in floc after ff: \$2 is: $2 9/25/2014 Course material created by D. Woit Course material created by D. Woit 33 33

More Related