yup, there is a simpler/better way, especially in Java or other OO languages.
The basic insight, first, is that your command parser is a finite state machine: the START state is an empty line (or index at the start of a line).
Let's think about echo
:
$ echo foo bat "bletch quux"
tokenize the line into pieces:
"echo" "foo" "bar" "bletch quux"
in a shell, the grammar is usually verb noun noun noun... so interpret it that way. You CAN do it with a sequence of if-else if things, but a hash is better. You load the hash with strings as indices, and index something else. It could be just a number, which would go into a switch:
(this is pseudocode):
Hashtable cmds = new Hashtable();
enum cmdindx { ECHO=1, LS=2, ...}
cmds.add("echo", ECHO); // ...
// get the token into tok
switch (cmds.get(tok)) {
case ECHO: // process it
// get each successor token and copy it to stdout
break;
...
default:
// didn't recognize the token
// process errors
}
EVEN better, you can apply the Command and Object Factory patterns. Now you have a class Command
public interface Command {
public void doThis(String[] nouns) ;
public Command factory();
}
public class Echo implements Command {
public void doThis(String[] nouns){
// the code is foreach noun in nouns, echo it
}
public Command factory(){
// this clones the object and returns it
}
}
Now, your code becomes
// Load the hash
Hashtable cmds = new Hashtable();
cmds.add("echo", new Echo()); // one for each command
// token is in tok
// the "nouns" or "arguments are in a String[] nouns
((cmds.get(tok)).factory()).doThis(nouns);
See how this works? You look up the object in the hash. You call the factory
method to get a new copy. You then invoke the processing for that command using the doThis
method.
Update
This may be a bit too general, in that it uses the Factory pattern. Why have a factory method? Mainly, you'd use that so that each time you execute a command, the "verb" object (like the instance of Echo
) can have its own internal state. If you don't need state to persist for a long time, you can simplify this to
(cmds.get(tok)).doThis(nouns);
Now it simply gets and uses the Echo
object you created when you instanciated it with cmds.add("echo", new Echo());
.