Ok, let's look today at how the shell executes commands. Sounds boring? You type the command, the shell locates it in the path, and executes it, right?
Well, not quite so. There are a couple of catches. First, there is the "+" sign at the end of the line. It is often misunderstood to continue the current command line at the next line, but then why
7.SCSI:> echo hello +
world
does only print "hello" and not "hello world"? On the other hand,
7.SCSI:> run +
list
runs the list command, indeed. So what's the difference between "echo" and "run"?
Well, the plus sign also inserts a line feed into the command line, and "echo" simply stops parsing its command arguments there. The rest of the string remains in the standard input of the command, at least if it uses buffered I/O, and waits there to be retrieved after parsing. "Run" parses multiple lines, but all other commands simply stop at the first line feed.
Anyhow, to return to the "+", the following demonstrates this:
7.SCSI:> ask "Please enter a number:" numeric to x
The shell will now kindly ask you to enter the number, so do it the pleasure:
Please enter a number: 42
Did this number arrive?
7.SCSI> echo $x
42
Yes. Fine so. But we can also feed the answer right into "ask" by using this little trick:
7.SCSI> ask "What do you get if you multiply six by nine?" numeric to x +
54
At this point, ask doesn't even wait for you to respond, but takes the 54 from the next line and pushes it into its input. Thus, the ask command returns immediately.
There is another magic token like "+", namely "&". This works like "run", actually very much like it, as it executes a command in the background:
7.SCSI> list &
7.SCSI>
[CLI 8] list suspended. [ViNCEd output]
7.SCSI>
Thus, the list command is started, run in background, but as it tries to write something to console, but is not the current console owner (see yesterday's episode), it is suspended. To continue, place it in foreground:
7.SCSI> fg 8
If you simply want to run a command in background, redirect its input and output to NIL: Of course, this does not make much sense with list, but anyhow:
7.SCSI> list <>NIL: &
Starts list in background, and returns to the shell.
Now, besides commands, we also have scripts. A script is a file whose "s" protection bit is set; these are typically found in S:, for example the "fg" command is one.
If the S-bit is set, the shell does something else. Usually, you would say "execute this as a shell script", but hold on, it's not quite that simple.
It first tries to determine the type of the script. If the first two characters of the file are "/*", i.e. forwards slash, star, then the file name is taken as is, a "rx" is prepended at its start, and the result is executed. Hence, execution is not done by the shell, but by ARexx. These two "magic characters" identify rexx scripts rather than shell scripts.
There are more "magic characters" than /*. These are #! and ;!, both work identical. If a file whose s-bit is set has them as first characters in the first line, the rest of the line denotes the name of a command to execute to run the script, and the rest of the command line would be given to this command. For example, if Amiga had a pyhton interpreter, the initial line "#! C:python" would run the python interpreter. But we can try something similar:
7.SCSI:> echo ";! C:ed" >ram:test
7.SCSI:> protect ram:test s add
7.SCSI:> ram:test
This makes the shell believe that "ram:test" is a script whose interpreter is the editor Ed, and by executing it, it gets run with the name of the "script to execute", namely "ram:test", as first argument.
Now, that's the S bit. But there is more. You know of course the feature that the shell implicitly executes a "CD" - change directory - if you just type in the name of a directory or device:
7.SCSI:> ram:
7.Ram Disk:>
But what does it do in case the file is not executable and not a directory? Well, even then the shell can do something, though it depends on setting the right variables. So let's help the shell a bit:
7.Ram Disk:> set VIEWER SYS:Utilities/Multiview
7.Ram Disk:> Guides:Shell.guide
Now, for that to work, I assume that you have "Shell.guide" in an assign named "Guides:", and that the "e"-bit, for "executable", of this guide is *NOT* set. If it is set, the shell will try to execute the "Shell.guide" as binary, and that of course gives you an "object is not executable".
The way how this is arranged here, however, the shell will determine that the input is a datatype, and will run this datatype through the "viewer", which is "Multiview". This "VIEWER" variable setting can be made permanent in ENVARC: if you like:
7.Ram Disk:> echo "Sys:Utilities/Multiview" >ENVARC:Viewer
and if the above example does not work, remove the "e" bit:
7.Ram Disk:> protect guides:Shell.guide e sub
Now, one final "feature" of the shell. Assume that you have the mmu.library in libs:
7.SCSI:> list LIBS:mmu.library
mmu.library 56952 ----rwed 30-May-14 12:01:44
1 file - 113 blocks used
7.SCSI:>
What does the following do?
7.SCSI:> LIBS:mmu.library
It prints mmu.library: Unknown command", even though the "command" is right in front of the face of the shell, and it is even an AmigaOs binary, and it even has its "e" bit set, so it should be executable. Why doesn't the shell then try to execute the thing?
The fact is, it actually does. However, libraries and devices are not loaded into the system like this, at least not normally (vnc.library is an exception, hear, hear). So what the "startup code" of the library does is to simply return a "-1" as return code to the shell. And this magic return code, undocumented to my very knowledge, tells the shell "hey, I'm actually not an executable, print an error to the user". Even though it is actually executed, though doesn't do anything useful.