CSCI 344
Intermediate Bash Scripts
Lab 5

Write the following bash scripts.  You may use the Internet as a reference for bash script syntax and as a reference for UNIX/Linux commands (such as wc and tail), but you may not search for solutions to these problems--that would completely defeat the purpose of doing these exercises.

When you complete one of the scripts, notify me and I will come watch a demo and give you credit for completing it.

Here is a link to the O'Reilly's Learning Bash.  Note: this link only works from computers in the csuchico.edu domain.

You may use any UNIX/Linux command or utility to solve these problems.




1)  (weight 1) Write a script that looks through all the directories in $PATH and finds all matches to the given command.  Then prompt the user using a select statement for which one of these commands should be run:

$ run ls
1) ./ls
2) /bin/ls
run command? 2
lines  ls  prompt  run  src
$

Hint:
use lab4::1 as a starting point.  Instead of printing all the matches, put them into a string and pass this string to the select statement.

When checking to see if a variable is null [ -z $cmds ]  if $cmds has the form "/bin/ls:/usr/bin/ls" and the IFS=:, the [ ] will complain that you have too many arguments.  You can fix this by quoting the $cmds: [ -z "$cmds" ].


2) (weight 1) Write a version of cat using the bash read command.  If the user specifies a valid file on the command line (it is a regular file and you can read it) use that file.  If not, prompt the user for a valid file (echo -n does not print the newline).  Keep prompting the user until a valid file is entered.

$ mycat
enter valid file? asdf
enter valid file? qwer
enter valid file? z
one - first line
two
three
four
five - last line
$


Hints:

A string can be read into the variable filename using the following syntax:

read filename
Assuming that the variable filename contains the name of a valid file, the entire file can be read one line at a time using the following syntax:

while read line; do
    echo $line
done < $filename

The read line reads the next line of the file into the variable line.  The "< $filename" redirects the input of the while loop to be the file named by the variable filename.



3) (weight 4) Write a script that counts the lines of all files in a given directory and reports the total by extension.  

$ lines ~/src/gpl
cpp: 4196
h: 3959
l: 192
y: 1561
$


Ignore files that do not have an extension (that is, they don't have a .).  

If a file has the form   <string1>.<string2>. ... .<stringN> assume that stringN is the extension.

If the argument is not a directory or if no argument is given, issue the following message and exit with an error status

$ lines foo
Usage: lines directory
$


Hints:

The command wc counts the lines in the given files.  When passing multiple files to wc the last line contains a total.  When passing one file to wc, the last line can also be thought of as the "total."  The command tail can help you with this.

In my solution I first find all the different extensions in the directory.  Once you know all the extensions you can use wc $dir/*.$cur_extension to count all the files.

When checking to see if a variable is null [ -z $extensions ]  if $extensions has the form "cpp:h:y" and the IFS=:, the [ ] will complain that you have too many arguments.  You can fix this by quoting the $expressions: [ -z "$extensions" ].

In lab I suggested you could use grep to find if you already have seen the pattern.  Since egrep recognizes the "|" for or, it is a better choice.  However, it is difficult to get it to work.  After an hour I gave up.  It is much easier to use a loop and loop through the extensions you have already seen than to use egrep.  Don't agree?  try a directory with a.cpp and b.pp and c.p and d.c.