Lecture 4

getopt gets flag letters from arg
OPTARG :When option is encountered, the value of the argument will be stored in the system variable OPTARG
OPTIND: Number of the next argument to be processed

6.11 Q) Write a script   my mail which will call mailx to send messages. The script should take an optional argument -s(to specify the subject) and one or more arguments to specify the recipients. If my mail is called without option -s it should prompt the user for a subject.
A) SUBJECT=""
     if getopt s:OPTNAME                #Valid option is 's'
     then                                                 #which takes an argument
            case $OPTNAME in
                 s) SUBJECT="$OPTARG";;           # The argument to 's' is SUBJECT
                ?) echo "Usage: $0 [-s subject] users"
                       exit 1;                                             # Exit if invalid option
              esac
     fi

      shift $(($OPTIND - 1))                                      #Remove the options
      USERS="$*"                                                         #The rest of the line
                                                                                       # is the recipients
      if [ -z "$USERS" ]                                                #which is compulsory
      then echo "Must specify recipients"
                exit 1                                                              #Exit if no recipients
       fi
      while [ -z "$SUBJECT" ]                                   #Loop until subject
       do                                                                             # is not null
                printf "Subject (no quotes):"
                read SUBJECT
        done

        mailx -s "$SUBJECT" "$USERS"

Advanced Shell Programming

$ command ls          user defined functions are not looked up.

$alias l1='ls -l'

7.1Q) By setting a trap on your login shell, arrange to be given the message Goodbye when you logout.
A) The signal EXIT is sent to your login shell when you logout, so use trap to perform an echo when this signal is intercepted:
$ trap 'echo Goodbye' EXIT

7.2Q) Write a function myusage which will print the total disk used by your home directory, preceded by a message reminding you of that directory's pathname.
A) $ myusage() {
      > printf "Directory %s uses " $HOME
      > du -s $HOME | cut -f 1
      > }

7.3Q) Write a script which will take one argument, assumed to be a filename, and run vi on that file using exec. If no arguments are given, the script should exit with return status 1.
A)
    # Check number of arguments
       if [ $# -ne 1 ]

       #  If too few arguments, warn user
       then echo $0 requires exactly 1 argument
                 # and exit with status 1
                  exit 1
        # otherwise run vi
        else exec vi $1
        fi

7.4Q) Create a script which will read a single line command and execute it
A) echo "Type a command:"                           #Prompt the user ......
      read CMD                                                      #read in the command..
       eval $CMD                                                #and run it
ls $HOME

uuencode will take a file and write to STDOUT a representation of the file containing only ASCII characters.
7.5Q) You have a long file called bigdata, which contains control characters, and you wish sam to have a copy of it. Arrange to send sam a copy via electronic mail.
A)   $uuencode bigdata bigdata | split #splitting into small chunks
       $ for i in x??
       > do
       > mailx -s "File $i" sam <$i
       > done
 

Makefiles

$ cc -c prog1.c
$ cc -c prog2.c
$ cc -o myprogram prog1.o prog2.o

$ cat >makefile
myprogram: prog1.o prog2.o
                 cc -o myprogram prog1.o prog2.o

prog1.o: prog1.c
             cc -c prog1.c

prog2.o: prog2.c
             cc -c prog2.c

$make myprogram

$make -n
cc -c prog1.c
cc -c prog2.c

Setting up a terminal

More on Files

Miscellaneous Utilities
 

Regular Expressions and Filters

Filter: Any command which reads from standard input, and writes data to the standard output.

UNIX programming involves transforming input, which is of known form, to output also of known form. The output depends on the input in a specified manner, and often involves creating a pipeline.

In UNIX , there are rarely unique solutions to problems. Want to choose solution which can be implemented fast and efficiently.

The purpose of commands such as grep, sed, tr and awk to provide speedy solutions for tasks which are frequently encountered, and which are difficult ot program using the shell alone.
 

Collating sequence

How are characters ordered??
Collating sequence is the logical ordering for the character set you are using. To change collating sequence amend locale

Range: Collection of characters which are consecutive within the collating sequence eg b-z

Character classes: letters, numbers, punctuations, marks eg: [:alnum:]
 
 

Character-to-character transformation

tr: Translating a file so that specific characters are replaced by others.

To capitalize all the lower case letters in the input:
$ tr "a-z" "A-Z"           or    $tr "[:lower:]" "[:upper:]"

$ tr "[:lower:]" "[:upper:]" < /usr/dict/words

Q) Write a filter which will replace all digits by blank spaces.
A)  $tr "[:digit:]" "               "

The 2nd arg of tr should not be shorter than the first.

$ tr ' ' 'B'          replaces all blanks in input with a B.

Q) Write a filter which will replace all double quotes by single quotes.
A) $ tr '"' "'"           or       $ tr \"    \'
 

"[X*5]"   == "XXXXX"
Q) Write a filter which will replace all letters in the first half of the alphabet by A and all in the second half by Z.
A)  $ tr "A-Ma-mN-Zn-z" "[A*26][Z*26]"

Q) Write a filter to delete all characters from the input which are not letters
A) -c option = non-alph characters, -d delete

   $ tr -cd "A-Za-z"    or        $ tr -cd "[:alpha:]"

Q) Replace multiple spaces by single ones
A) $echo " hello      there      chris" |  tr -s " '                -s squash
hello there chris

Basic regular expressions(BRE)

Pattern matching is very simple means of associating many strings which have a common pattern with a single string that describes that pattern.

BRE is said to match a string if
*  each part of the BRE with special meaning corresponds to a part of the other string, and
*  the other individual characters in the BRE and the string correspond.

Bracket expression:  Expr enclosed in square brackets. The expression enclosed by []  i s either a matching    : single chars, ranges, char classes
                      [ax-z[:digit:]]  matches a,x,y,z and any digit
or
nonmatching list : [^[:upper:]#]    matches any char which is neither upper case or a #.

[Cc]hris      will match Chris or chris

[[:alpha:]] ..      3 char string commencing with a letter.

[[:digit:]][[:digit:]]{{:digit:]]*   2 or more digits

^A.*E$     string starting with A and terminating with an E.
 

Q) What BRE will match a string which is just a sequence of digits?
A) ^[[digit:]][[:digit:]]*$
 
 

Extended regular expressions(ERE)

+ one or more consecutive occurrences
*  0            "             "
|     either or

[[:alpha:]]+[[:digit:]]? Any string starting with a letter, consisting only of letters, and terminated optionally by a single digit.

(xyz|ab) \.c        Will match either xyz.c or ab.c, and no other string.

Q) Write an ERE which will match any string which consists wither of only upper-case letters or only lower-case letters.
A)    ^[[:lower:]]+|[[:upper:]]+$
 

Selecting lines according to their content

grep :  A function to select lines from its input which match a BRE normally given as first arg.
             The BRE is known as a script.

Q)To print out all words ending in ise or ize from /usr/dict/words
A) $ grep 'i[sz]e$' /usr/dict/words

option
-E, grep will use ERE instead of BRE.
-F, fixed strings, no regular expressions
-c instead of copying matched lines, a count is given
-i   ignore case of letters
-f uses RE in filename
-v reverse behaviors
-l  ouput list of those files containing matching line

Q) How many words in /usr/dict/words commence with a vowel?
A) $ grep -c '^[AEIOUaeiou]' /usr/dict/words
     or   $ grep -ci '^[aeiou]' /usr/dict/words

Q) Suppose you have saved many mail messages in files in the current directory and u want to check file(s) whose subject has something to do with examinations. Each mail msg begins with Subject:
Eg: Subject:  Examinations
A) $ grep -l '^Subject:  .*[Ee][Xx][Aa[Mn]' *
     or
      $ grep -li '^Subject:  .*exam' *

Note: files with counterexamples and hexameters will be chosen too.
 

Stream editor(sed)

grep: Select lines from input and cp those lines
sed: In addition change those lines if required.

sed : {address command arguments} where address(which lines of input to take action) & arguments are optional

Addresses: empty-match all lines
                      number-match inputline number
                      num1, num2- match all lines in range[num1-num2]
                      $-match last input line
                      /BRE/-match any line matched by BRE

-f file arg
p copy pattern space explicitly to STDOUT
-n   no output at all

$ sed  '1,4d'     deletes lines 1-4 from input

$ sed 's/Chris/Sam/g'          will change all occurences of Chris to Sam

$ sed 's/^= /?/'     change each equals symbol at start of line to ?

$ sed 's/[:punct:]//g'  removes all punctuation

Q) Write a sed command that will remove all whitespace which terminates lines.
A) $ sed 's/[:blank:]*$//'

Q) Write a filer which will precede each word in /usr/dict/words which contains a capital letter by an asterisk.
A) $ sed '/[A-Z]/s/^/*/' </usr/dict/words   [A-Z] specify addresses
      or
      $ sed '/[A-Z]/s/^/*/' /usr/dict/words
 

Q) Write a filter which will output the last line of the input prepended by The last line is
A) $ sed -n '$s/^/The last line is /p'
$ is last line of input, command p to print

Choosing among these three filters

grep or tr or sed
Former two are faster since sed does more than the other 2 utilities.
 

Splitting a file according to context

$ csplit data 10
will take data and create 2 new files called xx00(lines1-9) and xx01(lines10-end)
File data remains unaltered. Size of each file printed STDOUT.

-f str : str is used as prefix instead of xx
-s silent suppress size pr
-n number Uses number decimal digits to form filenames  for  the file pieces. The default is 2.

Q) Split /usr/dict/words into three files called words00, words01 and words02, first 2 containing 10000 lines and final one the rest.
A) $csplit -f words /usr/dict/words 10001 20001
     To check length
     $ wc words??

Q) Split at line 1000 and then repeatedly every 1000 lines up to maximum of 2 times.
A) $ csplit -s /usr/dict/words 1000 {2}
$ wc -l xx??
999
1000
1000
rest

Q) Split /usr/dict/words into three files called w0, w1, and w2, each containing roughly equal number of lines
A)  $ LINES=$ (wc -l < /usr/dict/words )
      $ ONETHIRD=$(( $LINES/3 ))
      $ TWOTHIRDS=$(( $ONETHIRD * 2 ))
      $  csplit -f w -n 1 /usr/dict/words $ONETHIRD $TWOTHIRDS

Q) Split /usr/dict/words into two files, the first containing all words starting with chars up to and including m, the second starting with n thru z.
A) $split /usr/dict/words '/^[Nn]/'

Q) File book contains text for a book, with eachof the 10 chapters starting with a line
Chapter #: adghasf
Split this file into several files,c alled chapter00, etc one for each chapter.
A) $csplit -f chapter book '/ ^Chapter/' {9}