cs104 lab 7 more scripting (loops), $PATH I Loops Run a script with this loop (it takes no input): for thing in abc ls ghi pwd do echo thing $thing done Run it four mores times, replacing abc ls ghi pwd with each of these: 1) "abc ls ghi pwd" 2) ls 3) $(ls) 4) $@ (give this one some input) To be sure what $@ does, add the line: echo $@ (or echo "$@") Try it with lots of extra spaces in the input. Use one of these "for" loops and $@ to make a script named add: %add 6 8 12 0 1 sum is 27 It will make horrible error messages if an input is not a number -- that's fine. Use another of the for-loop tricks above to make a script that will count the number of things (files/directories) in the current directory. Then modifiy it (look under %info test -> file type tests) to count only the number of _directories_. Finally, modify it so if there is an input, it uses that as the directory to check (instead of the current one.) HINTS: #1 Figure out where to look first, and store it in a variable, maybe named $dir. #2 Remember command look in . unless you say otherwise. Ex: % dircount ~cs104 ~cs104 has 15 dirs b) while Scripts are not especially good for counting, but to practice with a simple while loop, make a script that prints any number of some letter: % rowof 5 a aaaaa % rowof 20 X XXXXXXXXXXXXXXXXXXXX HINTS: Start with count=0 and add one, while it hasn't gotten to $1. Remember "while" uses the same do-done as "for". c) shift Try these lines in a script: madeupname=$1 echo $@ "--" $# shift echo $@ "--" $# shift echo $@ "--" $# echo $madeupname What does "shift" do? Use shift and while to write an improved version of the "first lines" script which will take _any number_ of input files (first one is output file, like in lab 6): % top4 out.dat a.txt b.txt nothere % cat out.dat FIRST LINES: file with a's file with b's nothere does not exist The most obvious way is to save the output file name, then run "while there is a $1." II. using $PATH Make a directory src (stands for scripts) and move/copy one of your scripts to it. If you haven't done this before, go to some other directory and try to run that script by typing just the name. Then, just to verify common sense, try it with ~/src/. For another test, put a script in ~/src with ls in it and run that from elsewhere. Which directory did it list? How does a script determine its working directory? For fun, make a script that does just cd then ls . Check whether it works, and where you are when it finishes. Let's try to make it easier to run things in ~/src. Type "%echo $PATH" (which obviously prints the value of the variable $PATH, whatever that is.) One of the things in PATH is /bin. Try %ls /bin . Does anything look familiar? Try %/bin/ls If we add ~/src to PATH, we should be able to run scripts living there more easily. Try: %a=cat %echo $a %a=po$a %echo $a . Use a similar trick to add ~/src to PATH and check whether you can run things in ~/src from anywhere now. Was the ~ in ~/src expanded in PATH? III loop using _read_ (this is hard) Let's try to look at an entire file using for and cat. This is a script to see what chunks a "for cat" loop gives us. Are the chunks letters? Words? Lines?: for fileline in $(cat $1) do echo "---"$fileline"---" done We'd like to read different sized "chucks." _read_ will help do that. Try it in a simple script (it will wait for you to type lines. Try one with spaces. How much does it grab for $a?): read a echo "first thing is $a" read b echo "second thing is $b" Once you are happy with what read does, try this tricky script. Give it a large file as input (like info.txt). What new thing does this let us do (that "for a in $(cat)" won't?) Why isn't "read" reading from the keyboard anymore? cat $1 | ( read fileline while [ -n "$fileline" ] do echo "---$fileline---" read fileline done ) This is the hard part. Use the templace above to write a script to find all files of size N or more (use whatever ls -l says the size is) in the current directory and print their names. % bigfiles 1000 info.txt HINTS: o You need to use "read" since the output of "ls -l" has spaces. o Ingore the first line with an extra "read". o At first leave in "echo $---$fileline---" and test (output should be the same as "ls -l" with ---'s around each line.) o To get out the size and name, you can use one of two tricks: echo $line | cut -c??? | tr (remove spaces) or this bash shortcut: %line=abcdefgh %echo ${line:4} %echo ${line:2:3} This is in %info bash *Basic features:: *Shell expansion:: *Shell parm exp:: o Use a counter, but only add one if the size is big enough.