Using the GNO Shell More Productively And then one day, hooray! Another way for gnomes to say hooray! -- Syd Barret, The Gnome What Does This Command Do? If you are unfamiliar with what a particular command actually does or what arguments it accepts, you can check quickly by using the electronic manual. GNO/ME includes a utility called man which displays the manual pages for a command whose name you supply as an argument. The man utility uses another utility called more to actually display the pages nicely on the screen. Option Arguments As mentioned in , arguments are passed to a command to extend its usefulness. The arguments presented in the last chapter were words, such as foo, bar and foo.c. Standards exist under UNIX for programs to accept command-line option arguments. Option arguments (as the name suggests) are optional. There are two standards, short options and long options. Short options are characters that represent commands, whereas long options contain the entire option name. Consider the following output of the CATALOG command from ProDOS: /DEV NAME TYPE BLOCKS MODIFIED CREATED ENDFILE FINDER.DATA $C9 1 21-OCT-91 22:38 14-APR-90 18:24 260 FINDER.ROOT $C9 1 22-OCT-91 17:12 6-OCT-91 15:40 82 GENESYS DIR 1 21-OCT-91 23:37 25-APR-91 15:46 512 GSBUG DIR 1 21-OCT-91 23:38 19-JUL-90 16:48 512 MERLIN DIR 2 22-OCT-91 2:50 30-APR-91 20:21 1024 LIFEGUARD $B3 73 4-SEP-87 4:51 25-DEC-89 20:22 36608 ORCA DIR 2 22-OCT-91 17:12 14-SEP-89 18:27 1024 GNO DIR 2 22-OCT-91 17:12 13-AUG-91 16:36 1024 FAST.ANIM DIR 2 21-OCT-91 23:44 11-MAY-91 10:50 1024 MICOL DIR 2 22-OCT-91 3:10 14-JAN-90 2:46 1024 SRC DIR 1 21-OCT-91 23:44 7-AUG-91 20:30 512 NIFTYLIST DIR 2 21-OCT-91 23:44 29-JUL-91 4:04 1024 MCSRC DIR 1 21-OCT-91 23:45 7-AUG-91 20:34 512 BLOCKS FREE:43923 BLOCKS USED:21185 TOTAL BLOCKS:65108 It is impossible to get any variation in the format of this output. While the GNO/ME utility ls serves the same purpose as the command CATALOG from Applesoft BASIC, it has a wide number of options which can tailor the output to specific needs. Here is how ls can be used to give similar output to the CATALOG command: gno% ls -l :dev total 45k drw--rd 0000 dir 512 Oct 21 23:45 1991 MCSrc drw--rd 0000 dir 1024 Oct 21 23:44 1991 NiftyList drw--rd 0000 dir 1024 Oct 21 23:44 1991 fast.anim drw--rd 0000 dir 512 Oct 21 23:37 1991 genesys drw--rd 0000 dir 1024 Oct 22 17:29 1991 gno drw--rd 0000 dir 512 Oct 21 23:38 1991 gsbug drw--rd 0000 dir 1024 Oct 22 02:50 1991 merlin drw--rd 0000 dir 1024 Oct 22 03:10 1991 micol drw--rd 0100 dir 1024 Oct 22 17:28 1991 orca drw--rd 0000 dir 512 Oct 21 23:44 1991 src The -l short option argument tells ls to format the output in long format. ls supports only short options. If ls did support long options, the above command could be changed to ls +format-long. This is clearly more descriptive of what function ls will perform. For users to new to the UNIX environment, long format options are more user-friendly. However, advanced UNIX users prefer short options because of their brevity. As indicated above, ls has a wide number of options available to format the output. Use the command "ls -?" to get a short list of these options. It is left as an exercise for the user to discover how these options affect the output of ls. For a complete description of the ls command and its options use the command man ls. As an example of the usage and importance of long options, the following is the result of the +help option given to the coff utility. Note the use of both short and long options: coff [-OPTIONS] filename [segment..] [loadsegment..] OPTIONS DESCRIPTION -v [+version] display coff's version number -D [+default] disable default options -d [+asm] dump segment body in 65816-format disassembly -T [+tool] interpret Toolbox, GS/OS, ProDOS, ROM calls -x [+hex] dump segment body in hex (can be used with '+asm') -l [+label] print expressions using labels (default is offsets) -t [+infix] display expressions in infix form -p [+postfix] display expressions in postfix form (default) -m [+merlin] format of '+asm' to use merlin opcodes (default) -o [+orca] format of '+asm' to use orca/m opcodes -a [+shorta] assume 8-bit accumulator for disassembly -i [+shorti] assume 8-bit index registers for disassembly -s [+header] dump segment headers only -n [+noheader] do not print segment headers -f [+nooffset] do not print offset into file -h [+help] print this information, then quit filename name of file to dump [segment] names of segments in file to dump [loadsegment] names of load segments in file to dump The long options are much more descriptive, and provide a very easy way to remember options of programs. If an option passed to a shell utility program is not understood by that program, you will generally receive an error message stating that the option is not understood. If the program is user-friendly, a brief list of supported options will also be displayed. Entering Multiple Commands It is possible to give multiple commands to the GNO shell for processing. To execute multiple commands, place a semi-colon, ";", between them. The commands will be executed sequentially in the order they are entered on the command-line. Take care not to exceed the 4096 character command-line buffer. It is possible to execute multiple commands at the same time, this feature is discussed in . As an example, to run the echo command and the ls command in succession, enter the following on the command line: % echo Running ls ; ls -l The output of the preceeding command will display the string "Running ls" followed by the output of the "ls -l" command. Using Aliases gsh provides a built-in command, alias, which allows any command you would type on the command-line to be renamed. You are not limited to renaming a single command name. Rather, you could rename an entire command-line, which could allow you to use the name "backup" to execute the command "backup +source /system +destination /". The alias command is also a very powerful means of customizing your GNO environment to emulate other computing environments. To emulate the ORCA environment, the following aliases could be entered into your gshrc file, or a script called orca.alias that gshrc would run: alias copy cp alias cat "ls -l" alias catalog "ls -l" alias move mv alias rename mv alias delete rm alias type cat alias prefix cd alias create mkdir If you alias a string containing multiple words, you must enclose the string in quotes, as done for the catalog alias. gsh interprets the string as one value. If you do not include both the opening and closing quotes, the alias command will notify you of your error. You can view any alias' that are set by entering the alias command without any arguments. The setting of a particular alias can be viewed by entering one argument consisting of the name of the alias to view. If you wish to remove an alias, use the command unalias with the aliased name as the argument. To remove the aliases from the orca.alias file given above, you could do the following: %unalias copy cat catalog move rename delete type prefix create Unlike the alias command, the unalias command can take multiple arguments. See for further discussion of the alias and unalias commands. Redirecting Input and Output Most shell utilities write their output to the screen. However, under GNO/ME, like ORCA, it is possible to redirect that output to a file or a GS/OS device. The output of the ls command above was imported into this manual by redirecting it to a file. In addition to redirecting the output of a shell utility, it is also possible to redirect the input of that utility. Consider the following gsh session: [1]% echo this is a test this is a test [2]% echo this is a test > file1 [3]% cat file1 this is a test [4]% cat < file1 this is a test In the example above, cat takes input from "standard input". In command 3 above, cat takes as an argument the filename file1 and writes the contents of that file to "standard output". Where no filename argument is given, cat reads input from standard input and writes the output to standard output. In the case of command 4 above, cat contains no arguments and therefore reads from standard input. However, gsh interprets the "<" redirection operator and opens the file file1 for use as standard input. Therefore, cat will take its input from file1, even though it thinks it is reading input from standard input. This input redirection is transparent to the utility, making it work with most shell utilities. Command 2 above created a new file called file1. If this file had existed prior to the command then it would have been erased. It is possible to append output to the end of the file by using the ">>" redirection operator. Consider the following gsh session: [5]% echo second line >> file1 [6]% cat file1 this is a test second line Output that is sent to "standard error", can also be redirected. The ">&" operator redirects standard error to a file and ">>&" appends standard error to the end of the file. Below is a summary of the redirection operators: GSH Redirection Operators stdin stdout stderr redirect input from file < redirect output to file > >& redirect output to EOF >> >>&
Output can be redirected to a storage device, printer, modem, or any other valid GNO or GS/OS device. This provides a very powerful means of communicating directly with these devices from within gsh. One quick and dirty example of redirection allows a background version of gsh to be run on a terminal connected directly through the modem serial port: [1]% gsh < ttya > ttya >& ttya &
Pipelines In addition to the redirection operators, there is one additional operator which gives control over how input and output are handled. The operator is a pipeline, "|". Pipelines allow the standard output of one command to be used as the standard input to another command. This is almost equivalent to running the first command with its output redirected to a temporary file, then running the second command with its input redirected from the temporary file, then removing the temporary file. Pipelines make useful "filter" processes where the output of one command can be sent to another command which filters the output to whatever parameters you give the second command. As an example, you could display all the filenames with the character "a" in their name: [1]% echo foo > file1 [2]% echo abc >> file1 [3]% echo aabc >> file1 [4]% echo GNO >> file1 [5]% echo standard >> file1 [6]% echo oof >> file1 [7]% cat file1 foo abc aabc GNO standard oof [8]% cat file1 | grep 'a' abc aabc standard Pipelines are useful when you wish to view lines of text in a file that contain a phrase, or if you want to connect two programs directly, bypassing intermediate files. It is also possible to connect multiple commands with multiple pipelines. Pipelines are frequently used for paging output. The coff program mentioned previously prints the output of an OMF disassembly to the screen but does not pause when a key is pressed. In order to pause the display, the output must be piped through a paging utility. The ORCA shell requires that you wait for the entire command to complete execution before the pipeline is processed. However, GNO/ME executes both commands concurrently which allows the coff utility to execute while the paging utility displays the program output. GNO/ME comes with two page utilities, more and less. Complete desciptions of coff, more, and less can be found in the electronic manual using the man command. Background Execution of Commands A major benefit of GNO/ME is multitasking. Multitasking is a means of running multiple applications at once (not literally but very close). On the Apple IIGS, GNO/ME accomplishes pre-emptive multitasking by switching among applications that are running in the background. Any GNO/ME utility can be run in the background. Applications running in the background generally run for the same period of time (GNO/ME switches between applications 20 times a second). To background a shell utility, place the "&" character at the end of the command-line. The GNO shell displays a unique process ID and job number for each backgrounded command. It is possible to use the background character "&" to separate commands as with the ";" character. Each command with a trailing "&" is executed in the background. Up to 32 processes can executed concurrently under the GNO Kernel. Warning: When you exit the GNO Shell all processes will be terminated including any you may have running in the background. Below is a sample session with background tasks: [5] script> ps ID STATE TT MMID UID TIME COMMAND 1 ready co 1002 0000 0:45 NullProcess 2 ready co 1007 0000 0:05 gsh 138 running co 1006 0000 0:00 ps [6] script> cmpl +p script.c keep=script > outputfile & [1] + 141 Running cmpl +p script.c keep=script & [7] script> ps ID STATE TT MMID UID TIME COMMAND 1 ready co 1002 0000 0:45 NullProcess 2 ready co 1007 0000 0:05 gsh 141 waiting co 1006 0000 0:00 cmpl +p script.c keep=script 142 ready co 100B 0000 0:00 5/cc 143 running co 100D 0000 0:00 ps [8] script> cmpl +p script.asm keep=script1 > output2 & ps ; ls -s [2] - 145 Running cmpl +p script.asm keep=script1 & ID STATE TT MMID UID TIME COMMAND 1 ready co 1002 0000 0:45 NullProcess 2 ready co 1007 0000 0:05 gsh 141 waiting co 1006 0000 0:00 cmpl +p script.c keep=script 144 ready co 100E 0000 0:07 5/linker 145 ready co 100D 0000 0:00 cmpl +p script.asm keep=script1 146 running co 100F 0000 0:00 ps 147 ready co 1011 0000 0:00 5/asm65816 3 barf 1 outputfile 6 script.asm 1 script.root 1 foobar 19 script 3 script.c 36 script.sym 1 output2 6 script.a 6 script.mac 1 typescript [9] script> cp script.asm script2 & [3] 150 Running cp script.asm script2 & [2] - Done cmpl +p script.asm keep=script1 & [1] + Done cmpl +p script.c keep=script & [3] - Done cp script.asm script2 & [10] script> ps ID STATE TT MMID UID TIME COMMAND 1 ready co 1002 0000 0:45 NullProcess 2 ready co 1007 0000 0:05 gsh 151 running co 1006 0000 0:00 ps The first command line sends the ps command to the shell. ps lists the processes currently being executed by the GNO kernel. The processes named gsh and NullProcess are always present. For a complete description of the ps command, see . When a command is executing in the background, keyboard input is not sent to it. However, output is still treated in the same way. If the command sends output to the standard output or standard error, the screen will become cluttered. Try this example: [1]% ls -l& [2]% ls -l Both the output of commands #1 and #2 will be sent to the screen. After command #1 is entered and you begin typing command #2, you will see the output of the first "ls -l" command being sent to the screen while you enter command #2. Utilities which produce output should have their standard output and standard error redirected to a file when they are executed in the background. See . Executing commands in the background hinders the performance of the Apple IIGS. This is not too noticeable when one or two commands are being executed but performance will degrade more noticably as more commands are started. The Apple IIGS was not designed as a multitasking computer so the performance of GNO/ME should be understandable. If you have an accelerator (such as the Transwarp GS or Zip GS) installed, performance of multiple tasks will be acceptable. Job Control Now that command backgrounding and multitasking have been discussed, some more definitions can be mentioned. A process is a command which has been submitted to the shell for execution. gsh contains a set of special commands which make dealing with processes much easier. gsh treats each command entered at the command-line as a job, where a single job may contain multiple processes. For example: % ls one command, one process, one job % ls ; ps two commands, two processes, two jobs % ls & ps two commands, two processes, two jobs % ls | more two processes, one job When a job is run from the shell, it can be in several modes of operation. Jobs can be in any of three states: "running", "stopped", or "done". A job can be executing in either the foreground or the background. Commands exist to place a job in any mode of operation. When a job is run directly from a command-line it is running and it is in the foreground. Since the command-line cannot be accessed, two special keys have been defined: ^C kills the job and ^Z will stop the job. When the job is killed, it is gone forever, but a stopped job can be restarted. When a job is stopped, the kernel suspends each of the processes in the job. Jobs that are running in the background or have been stopped can be accessed using several built-in commands. The bg command will place a job in the background, placing it in the running state if necessary. The fg command will similarly place a job in the foreground, and the stop command will stop a backgrounded job. The kill command will terminate a job. Each time job control is accessed, a special job status line is displayed following the command. The first item on the left in brackets is the job number. Next is a single character, either a '+', '-', or a blank. The '+' designates the currently accessed job, the '-' is the previously accessed job, and all other jobs are not specified. The jobs command will display a list of all jobs. Have another look at the example in ; now more of the notation will be understandable. Each of the special commands, bg, fg, stop, and kill, take an argument which specifies the job to perform the operation on. The argument is either a number specifying the process id, or a '%' followed by one of the following: '+' or '-' for the current job, a '-' for the previous job, or a number to specify any specific job. If nothing follows the '%' or the argument is missing, then the current job is the default. There is one additional way that a job may be stopped. If the job is placed in the background and it attempts to read from the console, the job will be stopped, and the status line says "(tty input)" as the reason for the job being stopped. The job should be foregrounded so that the user may enter input to the program. It can then be placed back in the background as necessary (with ^Z and bg). Working with Pathnames To move easily to directories descended from the home directory, gsh provides the "~" (tilde) character. This character represents the home directory. Therefore, if your home directory was :hard:gno:home:root, you could use the command "cd ~" to move to the home directory (note that "cd" without any arguments also defaults to the home directory). To move to subdirectories of the home directory, you could use the command The tilde character is recognized by gsh before the command is interpreted. Another special sequence, "..", when used as part of a pathname, will strip the last path between pathname seperators. For example, the pathname "/dev/gno/.." would be expanded to "/dev". The "/gno" portion of the path is stripped as it is before the periods. This provides an excellent way to backup into your directories. "Backing up" is limited by the volume directory of the device being used. Additionally, the character "." can be used to signify the current directory. Pathname Expansion Many utilities supplied with gsh take, as an argument, a filename or filenames. The shell utilities cat, ls, grep, and cp can take multiple filenames as arguments. If you wish to invoke any of these utilities on filenames that have a sequence of characters in common (ie. AND, APPLE, SHK, TXT, FILE2, FILE3, etc), gsh provides special characters, called regular expressions or wildcards, which match multiple filenames without having to enter all filename arguments manually. GSH Wildcard Operators * Matches any string of characters. ? Matches a single character. [abc] Matches any of the characters enclosed in brackets. [^abc] Matches any of the characters not enclosed in brackets. [a-c] Matches the ascending sequence of characters enclosed in brackets.
This method of matching filenames is known as "globbing". gsh performs globbing on the word prior to executing the command. The following gsh session illustrates file globbing: [1]% cd /dev/gno/utilities [2]% ls :dev:gno:utilities CONV Crunch CrunchIIGS DeRez DiskCheck DumpObj Duplicate EMACS Equal Express Files LinkIIGS MakeBin MakeDirect OrcaDumpIIGS Prizm ResEqual Search canon choose clrff cmdfix coff compact count detab dir dirff dumpfile eject emacs.doc emacs.hlp emacs.rc emacs.tut help init join link macgen makelib mem online pageeject pause pwd src [3]% ls e* :dev:gno:utilities EMACS Equal Express eject emacs.doc emacs.hlp emacs.rc emacs.tut [4]% echo *r *m dir Prizm mem [5]% echo *i* cmdfix CrunchIIGS Prizm DiskCheck Duplicate Files init join LinkIIGS makelib MakeBin MakeDirect link dirff dumpfile online OrcaDumpIIGS dir [6]% echo NoMatch* No match. [7]% echo [a-f]* coff canon cmdfix compact Crunch CrunchIIGS DeRez DiskCheck DumpObj Duplicate EMACS emacs.doc emacs.hlp emacs.rc emacs.tut Equal Express Files choose clrff count detab CONV dirff dumpfile eject dir [8]% echo [a-fs-t]* coff canon cmdfix compact Crunch CrunchIIGS DeRez DiskCheck DumpObj Duplicate EMACS emacs.doc emacs.hlp emacs.rc emacs.tut Equal Express Files choose clrff count detab Search src CONV dirff dumpfile eject dir [9]% echo emacs?* EMACS emacs.doc emacs.hlp emacs.rc emacs.tut [10]% echo [^a-f]* Prizm help init join LinkIIGS makelib MakeBin MakeDirect link mem ResEqual Search src online pageeject pause OrcaDumpIIGS pwd macgen [11]% echo [^a-fs-t]* Prizm help init join LinkIIGS makelib MakeBin MakeDirect link mem ResEqual online pageeject pause OrcaDumpIIGS pwd macgen [12]% echo ??? mem src pwd dir [13]% echo ? No match. [14]% echo "???" ??? [15]% do you have a light? No match. As can be seen by the above example, character matches are case insensitive. The ProDOS file system treats the filenames "file" and "FILE" as the same file. gsh recognizes this and does not detract from the underlying file system. File globbing makes passing arguments to commands much easier and much more powerful. You could easily use "*.c" as an argument in a number of ways: [1]% ls *.C lists all filenames ending in ".C" [2]% cc *.C compiles all files ending in ".C" [3]% more *.C displays contents of all files ending in ".C"
Quoting Special Characters Beginning with Apple IIgs System Software 6.0, GS/OS is able to read files from Macintosh computers. The Macintosh uses a filesystem known as HFS, which allows filenames to contain any character except the colon (":"). Because a filename such as "emacs?*" is valid under HFS, care must be taken or unexpected results will occur. The word "emacs?*" was used as a regular expression above to specify a list of filenames beginning with the word "emacs" and one or more trailing characters. gsh does provide a way to pass an argument which contains special shell characters to a command. This is known as quoting an argument. There are three different ways to quote an expression: The single quote will quote everything between the single quote marks. Thus, to display the contents of a file on an HFS volume named "emacs?*", use the command: more 'emacs?*' The double quote will quote everything between the double quote marks except variables; echo "emacs?* $home" will product "emacs?* /dev/gno". See for more on variables. The backslash is used to quote one character. To pass "emacs?*" as a regular using the backslash, one could enter the following: ls emacs\?\* One additional purpose of the quoting mechanism built into gsh is to add spaces to command arguments. Each command and its arguments is separated by a space. Multiple spaces between arguments are treated as one space. Thus, consider the following: % echo a b c a b c % echo 'a b c' a b c How gsh Finds a Command gsh has a special variable, PATH, which specifies the directories and order of directories to search for shell utilities. This variable is often setup in the gshrc file although it can be changed as often as needed. The purpose of the PATH environment variable was discussed in . When gsh starts up, it searches all directories specified in the PATH environment variable and establishes a table of all commands, called a hash table. Because of this table, gsh "knows" where a command is and can execute the command much faster than searching through all directories every time the command is entered. The search process begins with alias names. See . If an alias is found that matches the command, the alias is replaced with its value and the command-line is again parsed. If it was not an alias, gsh checks to see if it was a special built-in utility. The search process then searches for the name in the hash table. If an entry is found in the hash table, the path name of the command is retrieved and the command is executed. If an entry is not found, the current path is searched. If the command name is not found, an error results. When the PATH environment variable is changed, gsh does not automatically recreate the command hash table. You need to issue the command rehash to recreate the hash table. The more pathnames specified, the greater the delay in starting gsh and in invoking the rehash command. The following shell script changes PATH and invokes the rehash command in one step. echo Resetting PATH variable $PATH to $1 set path=$1 rehash The $1 variable will be expanded with the first argument passed to the script. rehash should also be used if a new utility is copied to one of the directories specified in the PATH variable. Of course, it is possible to specify the absolute pathname of any command, but this is undesirable if the command is frequently used.