BeanShell

Discussion of the implementation of JnodeBeanShell.

JNode manipulation

One of the other nice things about bsh, is that (in theory) it can be used to directly manipulate JNode. That is, one could do things like:
shellman = InitialNaming.lookup(ShellManager.NAME);
and then proceed to play about with the ShellManager.

This should make JNode development easier, as one can try out little snippets of code in bsh.

bsh command names

There is a slight problem with integrating existing shell commands into bsh. Bsh uses class names for command names, so its CpuIDCommand rather than just cpuid. Some kind of aliasing is probably going to be needed to get around this. It shouldn't be too hard to modify bsh source so it uses some static method like getCommandName() to determine the name to use rather than the class name.

Command Name

It would be even easier to write a bsh script like:

void cpuid(){
print(org.jnode.shell.commands.CpuIdCommand.exicute(...));
}

Forgive me if the structure here is wrong but my point is we dont have to modify the beanshell to make shorter names.

Scripts versus classes

Taking your suggestion even further, we could just write bsh script wrappers for the existing commands, removing the need to implement invoke() methods in the command classes. Although, this may not be ideal for all commands, since invoke() allows the in/out/err streams to be properly redirected to bsh.

The advantage I had in mind with modifying bsh, is that it would reduce maintenance since one wouldn't need to separately maintain a bsh name alias script and a command class. Something like a static getCommandName() might also come in handy for other things...perhaps.

It looks like we have alot of flexibility in how we expose jnode commands to bsh Smiling

Bug

I commented on a bug related to beanshel earlier see) Until this is not fixed beanshell won't work.
I'm affraid that dropping the actual shell and making beanshell the default shell is not a really good idea. Beanshell can be an alternative shell but the extra typing compared to a normal shell would make it heard to use for eveyday puposes. Just like Linux, Jnode can have multiple shells. I think bsh could be more closely integrated with the actual shell. Defining a facility for easily extending the actual shell with beanshell scripts would be useful. So instead of replacement I propose integration.

Bug source

I was under the impression that the source of the bug was either, the command shell consuming System.in, or a problem in the classpath implentation.

If it is the first case then replacing the cmd with beanshell should resolve the problelm, if it is the second, then if we replace the cmd with beanshell it still will not work, in which case we will know more rightly where the problem lies.

Now, I do not mean to propose the instant switch from cmd to beanshell. I suggest that those who are interested in seeing the implementation of an object oriented commandline begin a development branch. We should make some plans, test the results and see what we get. I believe that the results will be greatly favorable to using the beanshell.

About the extra typeing, the addition of '();' to every line still does not compare the the simplicity of method overloading, and formal parameter types. The benifit outways the cost.

A beanshell prompt is different from 'normal' shells. But the computer industry defines normal as "old enough that everyone uses it." Jnode is a product of the revelutionary design of oop. I believe that by using familure names like grep and cat we can accomodate 'normal' users, while sustaining the power of the bsh system.

What do you think?

Would like to see an example

I browsed through some of the beanshell examples. What I've seen so far is _much_ more complicated to use than I'd expected for a shell. Some of the examples feature "magic properties" and then sourcing another (longish) bsh script.

I'd like to see a simple example, a one-liner, to perform a rather complex task like:

- rename all PDF files below the current directory to .pdf.old, extract their textual content and replace "foo" with "bar", saving them to "<base filename>.txt"
- find all "doc" paths on the harddisk and create a link to them at "/docs/<name of parent directory>"

Let's say all the needed commands (rename, find, grep, pdf2txt, ...) are given. Just want to see how effective piping combined with argument parsing can be achieved in BSH.

Complex Tasks

This is a valid point. Complex tasks requre piping in normal shells. In the beanshell that would be replaced either by method nesting or variable definition. The first example, which is the hardest could be done like this:

find("foo", "bar", "." /*output dir*/,"*.txt" /*output name*/, pdf2txt( rename("*.pdf.old", grep("*.pdf",true /*recursive*/))));

or like this:

files = grep("*.pdf",true /*recursive*/);
rename("*.pdf.old", files);
texts = pdf2txt(files);
find("foo", "bar", "." /*output dir*/,"*.txt" /*output name*/texts);

Now, both of these exampless are complex. But the normal shell equivolent would be of similar complexity and legnth given that there would be a great number of switches and flags to manage.
In fact, this example is so complex that I imagin most people would break it into smaller bits, no matter what shell they're on.

More importantly, both question and answere are flawed, because of lack of information. Does pdf2text return String[] or File[]? It cant do both. A true java find() method would not handle replacement or file renaming or file output for that matter. It would take a String and a regex and return an index or substring.

One of the reasons I support the BeanShell idea is to get away from the old system. Textural arguments are combersome. Finding out what a function actually does is difficult because of the numerous switches in the help printout. Handling very complicated tasks is complex with only piping.

All of thes issues are resolved in the beanshell. In a switch from cmd to bsh you gain power, exchange stroke lengths, and loose complexity.

What do you think?

Now you got me started ;)

Thinking about it, both approaches (imparative and functional) don't really seem to be an inherently good choice when it comes to fulfill command line specific tasks. This does not include shell scripts; completely different demands there. The command line must be quickly typable, able to provide auto completion, and be powerful for tasks that work on sets, trees and streams of information (structured text, flat and recursive directory lists, ...). Just trying to bend my mind around this problem. Here's what I have so far:

- a command typically can get it's input from different sources: stdout, files, sockets, ...

- this same command can also output to different channels at the same time, like producing verbose information about the progress while writing a file.

- to perform complex tasks, you have to "wire" several outputs to corresponding inputs, taking care they match in type or can be translated as needed

So let's say a command just provides different outputs and writes to them if they are wired. Generally, there's a "out", "log" and "err" output, but own ones can be declared.
Alike, it provides inputs and decides what exactly to do by inspecting which of those are wired, and which values the user-defined parameters have.

Now, with each command you can give an indicator on what output to wire (to which input). Something like:

command/output1/output3->input2(param1, param2->paramname)

You can wire in a kinda OOP manner:

echo("test").reverse/out()
outputs "tset"

You can use the implicit shell context (current dir, stdin, ...)

echo/position()
will output the current directory

Wiring outputs to multiple commands could work like this:

find/tree("*.pdf").{echo/filename()}{copy/file(".")}
finds all PDFs, outputs their name to stdout and copies them to the current directory

The thing I'm really unsure about, how to link outputs of different commands to the inputs of another. Thinking about some kind of variable here:

xsl=wget("http://me.com/my.xsl"); find/list("*.xml").process/file/xsl.out->xsl()
// processes all XML files in the current directory with an xsl provided on a web server

This seems to be quite similar to Microsoft's new shell approach IIRC, but I hadn't really understood it's merit until just now.
The whole approach is quite raw, but I think one can polish it; provided you people also understand what my sick mind is producing here.

BTW, the two tasks I asked for might look like this:

find/tree("*.pdf").rename/file(".pdf", ".pdf.old").pdf2text/file().replace/out("foo", "bar");

scope("/").find/tree("/doc/").link/parent("/docs");

Streams and Pipes

This is still a system of streams and pipes; flexible though it may be. It would fit much better into the current command line design than in the beanshell.