Assignment one questions and answers

Here are some questions and answers about assignment one. Suggestions for additions to this list are welcome (via e-mail).

Other resources:


Q: I uploaded my file at 11:45 last night [October 14th] and it didn't work at CDF, but it worked fine at home. May I have an extension on account of this?

A: No. It's simply not possible for us to accommodate problems with your own computer equipment. I suggest that you use the CDF computers, which are professionally managed; you can use the CDF computers from home over the net just fine; see remotelogin.html.

Use of your own equipment is at your own risk; I can sometimes assist you with it, and I'm not opposed to it, but if problems with your own computer were allowed to cause you to have extensions, everyone would have free extensions. It's just not feasible.

At this date [October 15th] it's a bit late for this information to be of use to you for assignment one. Fortunately I have a time-warp here so I'll post this on the course web page retroactively on September 27th. Please be advised.

When the due time approaches, just hand in what you've got; you have to move on with your other work, in this course and in your other courses. But also, please try to avoid last-minute problems by avoiding setting yourself up to have a major change in working environment right at the last minute, such as switching from your home computer to CDF. And you do have to make your program work at CDF, so just start there.

If you know in advance that you're going to be late for a good reason, please talk with me about it in advance; although be warned that my suggestion might be that you should simply submit in advance.

I'd also like to point out that even a zero out of 10% is far better than cheating and suffering an academic penalty. Don't cheat even if you're under pressure; and please re-read the section about academic offences at the end of the course information sheet. Whatever the penalty eventually applied for cheating, it will be worse than merely a zero on the assignment.


Q: (applies to the paper handout only) I can't understand the paragraph at the bottom of the first page about "at least one [command-line argument] is positive". Doesn't "zeller" require three arguments?

A: Oops; this paragraph is meant as a closing paragraph for the specification of "nimmove", not "zeller". I'm not sure how I mixed that up.

I've corrected it on the PDF file on the web page.

For zeller, it should say:

You can assume that all command-line arguments are well-formed positive integers, but you do need to check the argument count ($#).
For nimmove, it should say:
You can assume that all command-line arguments are well-formed non-negative integers, and that at least one is positive. However, you should emit a usage message in the case of no arguments.


Q: How do I submit my assignment?

A: Sorry, I seem to have managed to leave that off the hand-out. Oh well, the two pages were full anyway.

I suggest you begin by making a subdirectory to hold your assignment files, plus any other working copies and associated files. Please call your assignment files "zeller" and "nimmove". Your files must have the correct names to be processed by the grading software.

Once you are satisfied with your files, you can submit them for grading with the command

	submit -c csc209h -a a1 zeller nimmove
You may still change your files and resubmit them any time up to the due time. You can check that your assignment has been submitted with the command
	submit -l -c csc209h -a a1
(that's an "ell", as in "ls -l")

You can submit files individually instead of all at once, and you can resubmit a particular file by using the -f option, e.g.

	submit -c csc209h -a a1 -f nimmove
This is the only submission method; you do not turn in any paper.


Q: What should the exit status of my programs be?

A: If errors occur, the exit status should be non-zero -- you can use the actual exit status of a failing sub-command if available, or you can say "exit 1".

If no errors occur, the exit status should be zero, like all good unix processes. If you "fall off the end" of the shell script, the exit status will be the exit status of the last command executed, which will generally be zero since no error occurred, so your shell script will behave correctly.


Q: What do we have to do to comply with the guideline that "the properly-behaved shell script sets its own PATH variable"?

A: Just put "PATH=/bin:/usr/bin" (without the quotes) at the top of your shell script.

Q: What do we have to do to comply with the guideline that "the properly-behaved shell script removes any temporary files, at least in the case of normal termination"?

A: For this assignment, simply do not create any temporary files. There is no need for any temporary files for zeller or nimmove.


Q: What's the difference between "$@" and "$*"?

A: For assignment one, you don't have to worry about this because all of the user parameters are guaranteed to be well-formed integers.
But in general:

Consider writing:

 cat $* 
to pick up all arguments. (Let's suppose you put this in a file called "myscript".)

Try it with a command like this:

 sh myscript file1 'file two' file3 
(where "file two" has a space in the file name, so we quoted it).

This will expand to

 cat file1 file two file3 
So it will process file1 and file3 correctly, but instead of processing "file two" it will attempt to process two files, named "file" and "two".

So we need quotes. Suppose we try this next:

 cat "$*" 
Try it with a command like this:
 sh myscript 'file two' 
This works!
Now try it with
 sh myscript file1 'file two' file3 
No good. It tries to process a single file named "file1 file two file3".

What we need is a way to quote the individual arguments. If we knew there were three we could write: cat "$1" "$2" "$3"
but of course we don't know how many there are.

Enter "$@". It's the same as "$*", except for a special wacky rule that if it is within double quotes, it closes and opens the quotes between each parameter. E.g. in the case of

 sh myscript file1 'file two' file3 
, the command
 cat "$@" 
will expand to
 cat "file1" "file two" "file3" 

And the wackiness doesn't end there. There's another special rule that if there are no command-line arguments at all, "$@" expands to no arguments at all (i.e. not the empty string as a single argument, as you'd probably expect). So

 cat "$@" 
, if there are no command-line arguments at all, will be a simple "cat", which will process the standard input.


Q: How can I make it that you can just type (for example) "nimmove 1 2 3" instead of "sh nimmove 1 2 3"?

A: Two things:

  1. Make the first line of the file "#!/bin/sh", or at least, don't start it with a '#' unless the first line is "#!/bin/sh". (Note that this is a comment as far as sh is concerned; it's interpreted by the OS kernel to decide what interpreter to run, and it's designed to be ignored by the interpreter itself by beginning with a comment symbol.)
  2. Make it executable by typing "chmod +x nimmove".
You don't have to do this for this assignment. Right now we'll be content to run our shell scripts with "sh file"; you can do better, but that's not an sh topic, it's an exec() topic.


Q: Woo hoo! In my program you can type "zero" instead of 0 as a command-line argument, and I've added a random selection which outputs an amusing comment before proceeding, and ...

A: Don't do that sort of thing.

Follow the advice to "Keep It Simple". A more complex program is more likely to have bugs; it takes you longer to write; it is harder to maintain; it is unlikely to be more usable. That is to say, no user is going to type "zero" instead of 0 until you tell them about it. It's not helpful, and it is hurtful.


Q: What is the correct usage message for "zeller"? For "nimmove"?

A:
   usage: zeller year month day
   usage: nimmove nsticks ...
And remember that it has to be output to stderr (file descriptor number 2).

Q: What variations in the above are allowable?

A: Hardly any. You can either use $0 or "zeller" (or "nimmove") for the program name. And you may be able to argue for other one-word argument descriptions than "nsticks", etc. But the term "usage:", and the rest of the line looking like an actual command, is standard and must be followed. Furthermore, the meaning of the square brackets and ellipsis is standard -- "something ..." means one or more somethings, and square brackets mean "optional", so that altogether "[something ...]" means zero or more somethings. These meanings are discussed in the discussion of the "SYNOPSIS" section of the man page in Henry Spencer's How to Write a Manual Page document, which we might refer to for assignment two.


Avoid unproductive temporary variables, just as in C or Python programming. E.g. don't say

        something=`command`
        for i in $something
        do
            ...
if you're not later going to use the value of $something. Instead say
        for i in `command`
        do
            ...

And remember "for i" to loop through all command-line arguments, if that's what you want.

Although sh scripts tend to be a bit less pretty than programs in normal high-level languages, you should still make a little bit of effort in this regard. Indent lines to the appropriate nested indentation level, at least; and do use blank lines in the usual fashion.


At this point in CSC 209, confusion is often caused by overuse or too-early use of "shell functions". Don't start off by writing a bunch of functions. I suggest leaving any use of shell functions until near the end, and then only using shell functions if you have some repeated code to collapse.

In real life, we would not start by repeating the code and then have a subsequent cleanup phase; however, at this point in the course there tend to be a lot of bad decisions about when to use shell functions, which complicate people's code considerably. So I recommend against looking ahead that far in your sh code writing. Write it without using shell functions to start. Many people's intuitions as to when to use a shell function seem to be bad at this point in CSC 209.

In C or Java, everything is in a function.

In sh, most things are not in functions. Shell functions are a late addition to the language and are not crucial. Don't use them as much as you would in C or Java. Neither of my own solutions to this assignment uses shell functions.


Q: In zeller, is the second argument (the month) one-origin or zero-origin?

A: One-origin. No human ever writes months with zero-origin (such as 2 for March or 0 for January). Your shell script has to subtract one.

Q: Where's that sample python implementation?

A: zeller.py

Q: Hey, but that function treats the month as zero-origin!

A: Yes, the user input part doesn't; it calls zeller(year,month-1,day).

Q: Computing that formula with individual expr commands is very, very tedious.

A: I suggest you use dc instead.

Q: It seems to me it's much easier to use the built-in arithmetic functions of bash.

A: Perhaps. And it would be easier to write this program in Python, too. But the assignment is to write it in sh, and not using bash-specific extensions.

Q: But how do I provide the input to dc and get the results into a variable?

A: Same as everything so far; but you may be missing the fact that what's in the backquotes can be an arbitrary command, with redirections and pipes and everything. For example, an equivalent to

	x=`expr $y + $z`
is
	x=`echo $y $z + p | dc`

Q: And where are the tutorial notes about mock associative arrays in sh?

A: http://www.dgp.toronto.edu/~ajr/209/tut/02/associative.html


Q: In nimmove, the following bizarre code I got off the net for looping through the command-line parameters doesn't work.

A: Don't trust everything you read on the net. A simple "for i" loops through all the command-line parameters.

Q: What does "13 2o p" do as dc input?

A: "2o" sets the output base to base 2 (but the input base is still base 10). So this dc input is basically "13 p", which says to push 13 on the stack, then print the top of the stack. The only thing is that it prints it in base 2.

Q: Do dc or expr have an XOR operator?

A: No.

Q: So how does expr's addition operator help?

A: If the two numbers are in binary, adding them with expr is very similar to a bitwise XOR because expr will consider them to be in base ten so no carrying will occur. So the only difference between this operation and a binary XOR is that expr will output '2' for some digits which should be '0'. This can be solved with a tr, as mentioned on the handout.

Q: But if I add more than two numbers in this way, there might be '3's or higher digits in the output.

A: True. The above is only an algorithm for XORing two numbers, not any number of numbers. But you only need to XOR two at a time, in a loop.

And remember that 0 is the identity for XOR. So just as you add a bunch of numbers by starting with "sum=0", you can XOR a bunch of numbers by starting with zero.

Q: And how does that Nim strategy go, again?

A: nimstrategy.html


[main course page]