E - L Boyd: Loop Problems
E - L Boyd: Loop Problems
Loop Problems
1. What does the following loop do?
EXERCISES-LOOPS
Boyd
while read line; do echo "$line" >> output done 2. What command would do the same thing as the loop above? 3. If the above loop had been changed slightly and the second line used > rather than >>, what would be different about the result? 4. When does the loop end? 5. If you piped the output of cat file1 to the loop above, what would it do? 6. Again, assume you are piping the output of cat file1 to the loop above. Can you change the loop so that the combination functions the same as the command cp file1 output ? 7. Generate a list of empty directories beneath the current directory. 8. Change the permissions of all files beneath the current directory to 644 and the permissions of all directories beneath the current directory to 755. 9. You are writing a shell script that uses options -t -v -f -z and -p. The options, of course, can appear in any order. Write a sequence of commands for this shell script to examine the command line arguments and output an error message for each argument that is not -t -v -f -z or -p. 10.You have a directory that contains some files whose names are entirely in upper case, although they may include periods. Write a sequence of code to convert any such filenames to their lowercase counterparts. Your code should only translate names that are entirely uppercase - e.g., FOO.TXT or HELLO not Foo.txt or FOO.txt or Hello or hello. 11.Write a simple shell script that repeatedly prompts for a number and adds it to a total. When no further numbers are entered (indicated by typing ENTER) the total is displayed and the shell script exits. If the user types something that is not an integer, your shell script should output an error message and re-prompt for the number. The purpose of the shell script below is to output the name and size of the largest file in the current directory. It doesn't work. (Try it.) largestfile= largestfilesize=0 ls | while read file; do if [ -f "$file" -a -r "$file" ]; then thissize=$(wc -c < $file) if [ "$thissize" -gt "$largestfilesize" ]; then largestfile=$file largestfilesize=$thissize fi fi done echo \ "The largest file is $largestfile. It is $largestfilesize bytes long" 12.Why doesn't it work? 13.Propose two ways to fix the problem, changing the shell script as little as possible.
Exercises-Loops
CS 160B
Page 1 of 3
CS160B
Answers
EXERCISES-LOOPS
Boyd
1. It reads lines from standard input (the user at the keyboard?) and appends them to the file output. 2. cat >> output 3. The resulting file would consist of the last line typed (only) 4. When the user types ^D or standard input otherwise reaches end-of-file. 5. The same thing as cat file1 >> output 6. Simply delete the >> output from the middle of the loop and add > output to the end of the loop (after done), like this: cat file1 | while read line; do echo "$line" done > output 7. Here's the answer: find . -type d | while read dir; do nitems=$(ls -a $dir | wc -l) if [ $nitems -eq 2 ]; then echo $dir fi done 8. find . | while read name; do if [ -f "$name" ] ;then chmod 644 $name elif [ -d "$name" ]; then chmod 755 $name fi done for arg in $*; do case $arg in -[tvfzp]) ;; *) echo "$(basename $0): illegal argument '$arg'" ;; esac done 10. Here's a solution: #!/bin/bash ls | while read name; do if echo "$name" | grep -q "^[A-Z.]*$" ; then newname=$(echo $name | tr '[A-Z]' '[a-z]') mv $name $newname fi done 11. Here's a solution: #!/bin/bash total=0 while true; do echo -e "Enter number to add:\c" read ans if [ -z "$ans" ]; then break fi # the -? allows negative numbers Exercises-Loops CS 160B
9. Here's a solution:
Page 2 of 3
CS160B
EXERCISES-LOOPS
Boyd
until echo "$ans" | grep -Eq "^-?[0-9]+$"; do echo "That was not an integer." echo -e "Enter number to add:\c" read ans done ((total=total+ans)) # you c++ programmers: += works too done echo "The total is $total" 12. The problem is the pipe. A pipe separates processes, so the while loop is in a separate process from the main shell script. Thus, the main process never 'sees' the variables largestfile and largestfilelen changed. (In fact, the child process never gets a copy of the initialized variables either, but it doesn't matter since newly-created variables are initialized to empty and the integer value of empty is 0) 13. The solution involves keeping the variables largestfile and largestfilelen in the same process when they are calculated as when they are printed out. If you want to continue to use a while loop, just avoid the pipe by creating a temporary file: ls > /tmp/$$ls.out largestfile= largestfilesize=0 while read file; do if [ -f "$file" -a -r "$file" ]; then thissize=$(wc -c < $file) if [ "$thissize" -gt "$largestfilesize" ]; then largestfile=$file largestfilesize=$thissize fi fi done < /tmp/$$ls.out rm /tmp/$$ls.out echo \ "The largest file is $largestfile. It is $largestfilesize bytes long" A better solution involves using a for loop instead. If you use a wildcard to generate the list, this works fine: largestfile= largestfilesize=0 for file in *; do if [ -f "$file" -a -r "$file" ]; then thissize=$(wc -c < $file) if [ "$thissize" -gt "$largestfilesize" ]; then largestfile=$file largestfilesize=$thissize fi fi done echo \ "The largest file is $largestfile. It is $largestfilesize bytes long"
Exercises-Loops
CS 160B
Page 3 of 3