Rerouting, Piping, and EDLIN. ----------------------------- A distinguishing mark of MS-DOS / PC-DOS is without doubt the Command Line Interface. The user types a small line of text, which is in fact a simple sentence, that may be analyzed and executed by the command interpreter. The line is characterized by the following structure: OBJECT [subject / SUBJECT LIST] [PARAMETER / PARAMETER LIST] SUBJECT and PARAMETER are optional, and the order may be contrary to the one shown above. But OBJECT is determinant. Therefore, the Command Interpreter must be able to recognise it as one of the following: a. an internal command b. a .COM-file c. an .EXE-file d. a .BAT-file In the cases b, c and d, OBJECT must be retrievable through the PATH-string in the SET-environment. The following facts are true when the command line is entered correctly: - OBJECT determines what action will be done; - SUBJECT determines what the action is directed at; - PARAMETER determines how the action will take place. An example: DIR A: /W OBJECT = DIR SUBJECT = drive A: PARAMETER = /W The usage of Rerouting and Piping give the user a means to use another syntax than the one mentioned above. This is indicated by placing one or more of the following symbols in the command line: Symbol effect < (Rerouting) OBJECT obtains information from an external (ASCII-) file > (Rerouting) the result of the execution of OBJECT, which appears on the screen, is sent to an external file or device >> (Rerouting) as with the former one, the output is now added to the external file | (Piping) more than one OBJECT is used in the command line; the output of OBJECT (n) becomes input for OBJECT (n+1). An example: DIR C:\ | FIND "DIR" | SORT > SORTDIRS.LST to make a sorted overview of all the subdirectories under the current one. OBJECT (1) = DIR SUBJECT (1) = C:\ OBJECT (2) = FIND SUBJECT (2) = "DIR" OBJECT (3) = SORT and the same result would have been achieved if the following commands entered separately: DIR > FIRST.TMP FIND "DIR" FIRST.TMP > SECOND.TMP SORT < SECOND.TMP > SORTDIRS.LST ERASE *.TMP The second line might even be rewritten as: FIND "DIR" < FIRST.TMP > SECOND.TMP and a replacement for the second and the third line might be: TYPE FIRST.TMP | FIND "DIR" | SORT > SORTDIRS.LST without the final result being changed. In this example, SORTDIRS.LST is neither an OBJECT, SUBJECT or PARAMETER. Grammatically, one might consider it an adjunct. In most DOS-manuals the description of Rerouting and Piping is limited to the standard utilities SORT, FIND en MORE. In fact, SORT and MORE can only be used this way, but FIND can also be used in simple syntaxes as mentioned above, being the only OBJECT in the command line. But also many other DOS- utilities may use the feature, because their input and output is managed through the standard I/O-routine, which allows the use of Redirection and Piping. Here are some examples. Some will be quite familiar, others may not be known yet. The familiar ones were added to make the overview a bit more complete. 1. Symbol >, redirection to the NUL-device: COPY A:*.* B: > NUL This can be used in batch-files, to avoid the usual mess on your screen that was to be kept clean with the ECHO OFF command. 2. Symbol >, redirection to the NUL-device: ECHO your-own-text PAUSE > NUL To be used in a batch-file if you want to replace "Strike a key when ready" with a more suitable message. 3. Symbol <, feeding internal DOS-commands with file input: First, create a very small file, containing only the ASCII-character 03. For example, do this by writing the following script BREAK.DBG for DEBUG: BREAK.DBG --------- e 100 3 r cx 1 n break.fil w q and create BREAK.FIL with the command DEBUG < BREAK.DBG Only from within a batch-file, you can now you use the command PAUSE < BREAK.FIL and, when running the program, all you have to do is to press 'Y' to stop the program or 'N' to let it continue normally. From the DOS-prompt, you can use the command DIR /P < BREAK.FIL and the directory listing stops right after the first screen. 4. Symbol <, direct input for the SORT-Utility: If some words are to be sorted alfabetically, one way is to create an ASCII-file with the COPY CON method, and to sort its contents with SORT < ASCII.FIL > SORTED.TXT or TYPE ASCII.FIL | SORT > SORTED.TXT A faster solution may be the following command: SORT < CON > SORTED.TXT and when input is terminated with Control-Z, the sorted words will be put into SORTED.TXT. 5. Symbol <, create a temporary batch-file: Because input from the CON device can be redirected, an amusing experiment is the following one: MORE < CON which repeats all the lines you type until input is terminated. The lines are echoed to the CON device, so you can extend this line: MORE < CON | COMMAND After terminating the input with Control-Z the stored commands are executed. This is not a real batch-file, because there is no possibility for parameter testing or using the GOTO statement. Keep in mind that the last line must be an EXIT statement (and don't forget the Carriage return + Linefeed). An alternative is the statement CTTY CON, but in that case the second command processor still remains active in memory. 6. Symbol < or |, feeding internal DOS-commands with file input: When you delete all the files from a subdirectory with DEL *.* a confirmation from CON must be given. But this can be done automatically if you first create the small file YES.FIL: COPY CON \YES.FIL Y ^Z 1 File(s) copied or: ECHO Y > \YES.FIL and you may now delete all the files from the subdirectory with one of the following commands: DEL *.* < \YES.FIL or TYPE \YES.FIL | DEL *.* There is a small disadvantage, however. The file YES.FIL occupies one complete block on your disk, although it contains only a few bytes. If you look at the second way this file could be created, and the second way it was combined with the DEL-command, you may conclude that there is another way to get rid of your files: ECHO Y | DEL *.* and since you are dealing with a subdirectory, an alternative is ECHO Y | DEL . Very fast, and very dangerous indeed. If your DOS is adapted to another language, another character may be needed instead of the 'Y'. 6. Symbol < or |, feeding internal DOS-commands with file input: In a similar way, the DATE and TIME command can be feeded with a Carriage return + Linefeed, if you only want to know the current system date and time, without changing them. First, create the small file CARRIAGE.RTN: COPY CON \CARRIAGE.RTN {enter} ^Z 1 File(s) copied and the following commands will give you the information: DATE < \CARRIAGE.RTN TIME < \CARRIAGE.RTN From within a batch-file, you can make simple time reports this way: TIME < CARRIAGE.RTN >> TIME.RPT But again we have the disadvantage of the small file that must always be available, yet occupying one block on the disk. And again there is a way to solve the problem. When you enter the command VER (to inform about the DOS- version), the given output starts with an empty line. So try these two commands: VER | DATE VER | TIME For this matter these commands are no faster than the one using a small disk file, because temporary files are created when using the Piping option. You can prove this with the following experiment: A: (remove diskette from drive A:) VER | DATE and DOS will ask you whether it should Abort, Retry or Ignore, although VER and DATE don't need disk access when entered separately. 7. Symbol <, data protection with DEBUG: In the third example an input script for DEBUG was used to create a binary file. Many beautiful scripts have been made for DEBUG, most of them being assembler listings for small DOS-utilities. No assembler listing will be given here, but a way to make confidential files unreadable before erasing them: COPY CON DESTROY.DBG F 0 FFFF 8 W Q ^Z 1 File(s) copied The command DEBUG {filename.ext} < DESTROY.DBG entered before the command ERASE {filename.ext} will replace all the characters in {filename.ext} with a Backstep. Even if somebody unerases the file, the command TYPE {filename.ext} will only advance the cursor one line, as if the file were totally empty. Some people would prefer replacing all the characters of {filename.ext} with the ASCII-sign 7 (bell or beep), but I think that this world is already too noisy. If you want to use this method on a .EXE or a .HEX file, you should first rename its extension. 8. Symbol < or |, automatic diskette formatting: Even for programs like FORMAT, Redirection can be useful. First, make an input script: COPY CON A.FMT {enter} N{enter} ^Z 1 File(s) copied and, either at the DOS-prompt or from within a batch-file, use the command FORMAT A: < A.FMT or, with the alternative syntax TYPE A.FMT | FORMAT A: If you use DOS 4.00, A.FMT must begin with TWO empty lines, because that version of FORMAT always asks for a volume label. But you may want to format a large number of diskettes, all having the same volume label. In that case, enter the desired label at the second line. Instead, also the command LABEL A: < A.LBL may be used (you should now be able to write a correct script for the LABEL-utility). 9. Symbol >, storing batch-file output: If you start writing an article about DOS with some useful hints, it would be rather silly to execute a batch-file, and to retype its output into a text file that becomes a part of your article. Although the output of DOS- commands can be redirected into a textfile, this won't be possible with batch-files: the command BATCH > {filename.ext} produces nothing useful. This is where COMMAND.COM helps: just type COMMAND > {filename.ext} and start entering the commands. Type very carefully, because ALL output to CON is sent to the file. Terminate with the EXIT command, and add the created {filename.ext} to your article. 10. Symbol |, quick GWBASIC calculations: In addition to example 5 and example 6, where ECHO was used to pass an input string to another command, here's one for GWBASIC-lovers: ECHO FOR X = 1 TO 10 : PRINT X, X^2 : NEXT X | GWBASIC The statements are executed immeadiately, and return to system is done automatically. So, also GWBASIC accepts redirection. This makes it possible to use an alternative way to run a GWBASIC program from the DOS-prompt, with automatic return to the system. One way is to put the statement SYSTEM somewhere in a program line. Another way is to create an additional textfile RUNFILE.GBI. The extension .GBI is my own idea, it stands for Gw- Basic-Instructions. If you are familiar with the use of NC.EXT in the program Norton Commander, you can enter this as a definition: GBI: GWBASIC < !.! The .GBI-file may be created in the following way: COPY CON RUNFILE.GBI LOAD "MYPROG.BAS" RUN SYSTEM ^Z 1 File(s) copied and the matching DOS-conmmand will be: GWBASIC < RUNFILE.GBI You can even put the whole program into a .GBI-file, thus combining the program lines and the instructions: COPY CON SQUARE.GBI 10 FOR X = 1 TO 10 20 PRINT X, X^2 30 NEXT X RUN SYSTEM ^Z 1 File(s) copied Attention: there is a substantial difference between such a .GBI-file and a .BAS-file in ASCII. The latter one is really a program that is loaded into memory, but the .GBI-file is just a set of instructions that start building the program when the file is being read. You can see this happen if you run the GWBASIC-program from a .GBI-file: all the lines are copied to the CON-device. If you run a big program this way, use redirection to NUL: GWBASIC < RUNFILE.GBI > NUL if that doesn't disagree with the program itself. If the GWBASIC-program requires keyboard input, the trick won't work. But it can be very well used for small programs which set up your printer, etc. ----------------------------- So far, so good. Some nice examples have been shown in relationship to Rerouting and Piping. The following ones will be related to one small but useful DOS-utility that was not presented yet: the famous (or notoriuos) line editor EDLIN. To start with some basic knowledge: when editing a text file with EDLIN, there are two groups of editing comands. The commands in the first group are entered at the EDLIN-prompt, the asterix. They consist of (line) numbers and upper- or lowercase letters. The commands in the second group (function keys, arrow keys, INS and DEL) are used when (re-)editing one specific line. Let's first spoil the surprise: Both kinds of commands can be used in an input script for EDLIN, when using the familiar syntax EDLIN EXAMPLE.TXT < INPUT.ED But you should mind some restrictions: - don't load TSR-programs like CED before using EDLIN, because they disable the way EDLIN (and DOS) use their command line buffer; - no If-Then statements are possible, as in macro commands of some very sophisticated editors. Therefore, some details of EXAMPLE.TXT must be known in advance; - some EDLIN-commands may not be used: the QUIT-command and the ?-option in searching and replacing strings, since they require confirmation from the CON-device. CON is disabled when using redirection, so this will lock the system. After the reset, you will notice an unchanged EXAMPLE.TXT and an empty EXAMPLE.$$$. - if DOS 4.00 is used, avoid the List and the Page command. If some lines are too long, again confirmation from CON is required to continue the scrolling. All the other EDLIN-commands can be used in any creative way you might wish. After issuing the command DIR > EXAMPLE.TXT from a subdirectory, the following INPUT.ED removes the initial disk information and the indication about remaining free bytes INPUT.ED -------- s.. ; search string 1,.d ; delete from first to current line sFile(s) ; search string .,#d ; delete from current to last line e ; end In this way, you can cut any block of text from a bigger document, if you are certain about the strings at the beginning and the end of the block. For example, if you have marked a piece of EXAMPLE.TXT, beginning and ending with the unique strings BBBBB resp. EEEEE, here is a way to solve the problem with EDLIN: HEAD.ED ------- 1sBBBBB ; look for beginning 1,.d ; delete from first to current line e ; end TAIL.ED ------- 1tEXAMPLE.TXT ; load text 1sEEEEE ; look for end mark .,#d ; delete from current to last line e ; end To cut out the block from EXAMPLE.TXT, enter the following commands directly or from a batch-file: EDLIN EXAMPLE.TXT < HEAD.ED EDLIN CUT.OUT.TXT < TAIL.ED COPY EXAMPLE.BAK EXAMPLE.TXT Of course you can, when using a batch-file, experiment freely with parameter passing, etc. The T-command in TAIL.ED is an interesting one, because it can also load hidden files, just like the L-command in DEBUG. However, EDLIN cannot write to a hidden file. But with the T-command you can easily peek into a hidden AUTOEXEC.BAT by T-ing it into a temporary file (from DOS: EDLIN X.TMP), which you even don't have to save (use the Q-command). Here's one to duplicate all the lines in EXAMPLE.TXT DOUBLE.ED --------- 1,1,1c ; duplicate first line 1,2,#m ; move block to end e ; end If the initial EXAMPLE.ED has 10 lines, you might enter from DOS: FOR %T IN (1 2 3 4 5 6 7 8 9 0) DO EDLIN EXAMPLE.TXT < DOUBLE.ED or use less parameters, repeating the command with Function key 3. If you want to minimize keyboard operations, the number of characters in the FOR..DO command and the number of F3+{enter} keystrokes should be more or less equal. The following two scripts can be used to transform a complete ASCII-text to upper or lower case. UPPER.ED LOWER.ED -------- -------- 1,#ra^ZA 1,#rA^Za 1,#rb^ZB 1,#rB^Zb {etc.} {etc.} {etc.} {etc.} {etc.} {etc.} 1,#ry^ZY 1,#rY^Zy 1,#rz^ZZ 1,#rZ^Zz e e They may be used to fix up the appearance of program source code, or to change short system messages. These scripts cannot be created with the COPY CON method, because the first ^Z would become an EOF-marker. They must be created with EDLIN, or with another editor that can handle the ^Z-marker as a text character. If a very large text is being converted to upper or lower case, an extra script must be created that begins with a Write-command (W) and an Append-command (A) to load the next part of the text: UPPER_1.ED ---------- W A 1,#ra^ZA 1,#rb^ZB {etc.} {etc.} {etc.} 1,#ry^ZY 1,#rz^ZZ e UPPER_2.ED ---------- W A W A 1,#ra^ZA 1,#rb^ZB {etc.} {etc.} {etc.} 1,#ry^ZY 1,#rz^ZZ e UPPER_3.ED ---------- W A W A W A 1,#ra^ZA 1,#rb^ZB {etc.} {etc.} {etc.} 1,#ry^ZY 1,#rz^ZZ e When adding lines to a text, or changing lines, EDLIN must be put into the input mode. This is done by indicating the concerning line number, which may be combined with the Insert-command. When the input is done, you can leave the input mode by pressing Control-C or entering Control-Z (or Function key 6). When creating the script with EDLIN, use Control-V + C to build the Break-command. Control-Z can not be put at a line beginning this way, because EDLIN would return to its command mode. The Control-V method doesn't work from the DOS-prompt. But there is yet another method to simulate the Function keys in an input script for EDLIN. Some additional information is needed to understand this method. If you press an Arrow key, a Function key, a Page Up/Down, Home/End or Insert/Delete key, a sequence of two characters is sent from the keyboard. The value of the first one is always zero, the value of the second one (the extended key code) is different for each key. Only the following keys are relevant when using EDLIN: KEY 2ND VALUE 2ND CHAR MEANING F1 59 ; copy character from input buffer F2 60 < copy to next character pressed F3 61 = copy rest of input buffer F4 62 > delete to next character pressed F5 63 ? replace input buffer F6 64 @ stop input mode, string separator Left 75 K move one position to the left Right 77 M move one position to the right Ins 82 R insert characters into buffer Del 83 S delete characters from buffer EDLIN will easily accept a sequence of a zero-character and an extended key code in an input script. When using the COPY CON method to create such a script, the extended key codes can be entered normally. And the zero-character? You cannot enter it with the Alt-key, but from the DOS-prompt, the 7-th function key solves the problem. Let's assume an EXAMPLE.TXT which contains but one line: "The second word is removed." and that is exactly what EDLIN will automatically do when using the following INPUT.ED: INPUT.ED -------- 1 ; edit first line {F2}{space}{F4}{space}{F3} ; copy to space, delete to space, copy rest e ; end in which the second line is entered as: {F7} < {space} {F7} > {space} {F7} = Now you can start the operation: EDLIN EXAMPLE.TXT < INPUT.ED End of input file *1 1:*The second word is removed. 1:*The word is removed. *e Here is another example: Look for the first line containing the string "QWERTY", and delete the last two characters of that line. INPUT.ED -------- 1sQWERTY ; look for string . ; edit current line {F3}{Arrow-L}{Arrow-L} ; copy buffer, step back 2 times e ; end The third line is entered as: {F7} = {F7} K {F7} K These two examples are only of theoretical interest, of course. But they show that some very complicated operations can be described in an input script for EDLIN. I have used this method in the following situation: A batch-file MYPROG needed to be run several times, each time requiring the name of a subdirectory as a parameter. Almost every week, some subdirectories were added or deleted, so there had to be created a flexible system. Although the command DIR *. may give you a list of subdirectories, it is not possible to use the command FOR %T IN (*.) DO CALL MYPROG %T because the parameters in as FOR..DO loop must be filenames. The solution was set up in the following way: STARTER.BAT ----------- ECHO OFF CLS DIR | FIND "DIR" > DIRS.LST EDLIN DIRS.LST < REALDIRS.ED > NUL REALDIRS.ED ----------- S.. 1,.D E STARTER.BAT makes a list of subdirectories, and the directory entries . and .. are removed by EDLIN, using the script REALDIRS.ED. Now, the batch-file MYPROG.BAT can be used repeatedly: FOR %T IN (1 2 3 4 5 6 7 8 9 0) DO CALL MYPROG.BAT MYPROG.BAT ---------- ECHO OFF CLS TYPE DIRS.LST > SUBPROG.BAT EDLIN SUBPROG.BAT < 1-SELECT.ED > NUL EDLIN DIRS.LST < 1-REMOVE.ED > NUL SUBPROG Each time, SUBPROG.BAT is replaced with the remaining contents of DIRS.LST. Only the first line is used, because it contains the crucial information; i.e. the next directory name. Look at 1-SELECT.ED to see how that is being transformed into a new subroutine. The script 1-REMOVE.ED is a very simple one; it only removes the first line of DIRS.LST. In the third line of 1-SELECT.ED, {INS} was entered as {F7} R, {F2} was entered as {F7} <, and in the seventh line {F6} was entered as {F7} @. 1-REMOVE.ED ----------- 1d ; remove first line e ; end 1-SELECT.ED ----------- 2,#d ; delete rest of file 1 ; edit first {INS}call TESTPARM.BAT {F2}{space} ; put command before directory name #i ; append (2) other commands cd \workdir ; return to working directory echo ^G ; end signal {F6} ; enter input mode e ; quit EDLIN In the file TESTPARM.BAT, which contains the very DOS commands to be executed, you can check for parameters. If the last line of DIRS.LST is reached, TESTPARM.BAT receives no parameter, and the job is finished. Look at the {F2}{space} combination in 1-SELECT.ED; which is meant to avoid copying the string "