home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
msdos
/
sndbords
/
proaudio
/
fddmairq
/
fe.doc
< prev
next >
Wrap
Text File
|
1992-07-07
|
18KB
|
593 lines
fe - copyright SHARK, 1991.
FOREACH - Command List Processor with Member Substitution and Modification
Programmer Bart Crane
Syntax
fe [-deq] [var] -llistfile commandfile arg1 ...
fe [-deq] [var] ( member ... ) do command [; ...]
fe processes a list of commands on each of a number of words,
substituting each into the $-prefixed embedded variable "var",
while performing certain modifications to this word. fe also
searches the environment for embedded DOS variables and can
use the DOS branching facilities "if ...", "goto" and labels.
Options
-d debug, no execution, display processed command line
-e echo, display command line during execution
-q quiet, no prompting question mark
Members
fe has two methods of specifying the list of words to be substituted
into the command line:
( member ... )
this indicates that each "member" between the
parentheses makes up the list, with members
separated by whitespace.
-l listfile
"listfile" is the name of a file containing members.
if list is "-", then the standard input is read.
No space is required between -l and its argument.
Members are separated by newlines.
fe also will expand a pattern to a range of members:
[0-9] expands to 0 1 2 3 4 5 6 7 8 9
[a-z] expands to a b c ... x y z
[A-Z] expands to A B C ... X Y Z
"subranges" of each range are possible:
[4-6] expands to 4 5 6
[c-q] expands to c d e ... o p q
The range can comprise of a string:
[000-999] expands to 001 002 003 ... 997 998 999
[aaa-zzz] expands to aaa aab aac ... zzx zzy zzz
[AAA-ZZZ] expands to AAA AAB AAC ... ZZX ZZY ZZZ
and subranges of these strings are available, except
that aaa-fff expands to aaa aab ... aaz aba ... ffe fff.
Variables
fe accepts a string to act as the variable in the command line.
In order to access the variable to allow substitution, preface
the string in the command line with a dollar sign ($).
var "var" specifies a string (usually short: i)
searched for in the command line; when found
following a "$", the current word in the
list is substituted:
$var = current word from list
a missing "var" specifies "i":
$i = current word from list
fe modifies the word to be substituted in order to
make possible complex file-management commands by
simply appending a string to the variable in the
command line:
Assume: i = d:\sub\dir\filename.ext
$i:t :t = filename.ext leave lowest path element
$i:h :h = d:\sub\dir remove lowest path element
$i:e :e = ext leave extension
$i:r :r = d:\sub\dir\filename remove extension
$i:d :d = d: leave only the drive designator
$i:s :s = \sub\dir\filename.ext remove the drive designator
$i:f :f = filename.ext leave the filename element
$i:p :p = d:\sub\dir leave the pathname element
(:f and :p are not implemented prior to version 4)
Also, the numbers 1 through 9 cause only upto that number of
characters of the variable to be left:
$i:1 :1 = d leave one character
$i:2 :2 = d: leave two characters
...
$i:9 :9 = d:\sub\di leave nine characters
Note that modifiers can be concatenated and strings emebedded:
$i:h:t :h = d:\sub\dir remove lowest path element
:t = dir then leave lowest path element
a:$i:t:r.$i:e:20
= a: embed "a:"
:t = a:filename.ext leave lowest path element
:r = a:filename remove extension
= a:filename. embed "."
:e = a:filename.ext append extension
:2 = a:filename.ex leave 2 chars of extension
= a:filename.ex0 embed "0"
Assuming i = d:\dir\sub\filename.ext
copy $i a:$i:s:r:70.$i:e
will expand to
copy d:\dir\sub\filename.ext a:\dir\sub\filenam0.ext
Assuming i = d:\dir\sub\filename.ext
echo $i:d $i:s:h $i:t:r $i:e
will expand to
echo d: \dir\sub filename ext
effectively breaking up the fully qualified file specification
into its component parts. This logic fails if the lowest
component is not a file name:
Assuming i = d:\dir\sub
echo $i:d $i:h:s $i:t:r $i:e
will expand to
echo d: \dir sub
which may not be the desired result.
Version 4 and above handles this instance correctly:
Assuming i = d:\dir\sub
echo $i:d $i:p $i:f:r $i:f:e
will expand to
echo d: \dir\sub
and will result in the same output as above when the lowest
component of the specification is a file name:
Assuming i = d:\dir\sub\filename.ext
echo $i:d $i:p $i:f:r $i:f:e
will expand to
echo d: \dir\sub filename ext
(These modifications are similar to those found in the Unix
C-shell, with enhancements for functionality under the DOS
environment; specifically, the :d, :s, :f, :p, and :0-9 are
artifacts of the fe program, and the :e is found in only some
C-shell flavors.)
fe also has several internal variables for specifying DOS special
characters:
$P = | $R = > $A = >>
$I = < $Q = "
Note: conflict will develop if the main loop-variable
specified is one of these above:
fe A ( 1 2 3 ) do echo $A
This will produce undesired (probably) results, as
the command line generated will be "echo >>", and
not "echo 1", "echo 2", and "echo 3".
fe also processes environment variables in the command line in a
manner similar to DOS, in that strings between sucessive percent-signs
are converted to upper-case and searched for in the environment; if
not found, the DOS variable is stripped from the command line, else
the environment string found is inserted.
Commands
There are three ways to specify to fe the commands to execute:
the default operation is to prompt for the commands
(with a "? ") which are then read from standard input.
fe i ( 1 2 3 )
? command line 1
? command line 2
? end
read the command file "comfile" if it is present on the
command line.
fe i ( 1 2 3 ) \bat\comfile.bat arg1 arg2 ...
within comfile.bat, %1 is substituted with arg1,
%2 with arg2, etc.
execute the commands specified on the command line when
they are prefixed by the keyword "do".
fe i ( 1 2 3 ) do command line 1 ; command line 2
the semicolons are interpreted as newlines,
each command is processed for member-substitution
and then executed in order.
A line beginning with a colon specifies a label as in DOS batch
files; this line is not executed and can be a target for a "goto"
statement.
fe supports the DOS "if [not] exist", "if [not] str == str",
"if errorlevel X", and "goto" statements and ":str" labels. Thus,
many simple .bat files can be executed using fe. In addition, fe
also provides additional tests and allows these substitutions:
If Phrase Substitution
errorlevel = e same as DOS
exist = x same as DOS (test dirs = FALSE)
not = ! same as DOS
isdir = d TRUE if name is directory
iszero = z TRUE if name is file and is zero size
Branch Control Meaning
continue = skip remaining commands, process next member
next = (same as above)
restart = process commands again using current member
redo = (same as above)
ret = exit program, return to DOS last LOGIC test (0 or 1)
ret e = exit program, return to DOS last ERRORLEVEL
ret N = exit program, return to DOS N= value
This shortens the length of scripts or "do" commands:
if errorlevel 1 = if e 1
if exist file.ext = if x file.ext
if not exist file.ext = if ! x file.ext
Note: internal DOS commands, such as DIR and DEL, always return 0.
The fe program uses the "spawnl()" function to execute external
.exe and .com programs, and the "system()" function to execute ".bat"
programs and those commands not found in the PATH.
Also, fe returns to DOS the value of the last "if" test, where a TRUE
is returned as 1, and FALSE is returned as 0. Further, the expression
"ret N" where N is the value to return to DOS, exists, and so fe can be
used for more sophisticated testing than is available through DOS in a
.bat file, yet allow the branching from within that .bat file:
if "%1" == "" goto quit
fe do if d %1 ret 3 ; if z %1 ret 2 ; if x %1 ret 1
if errorlevel 3 goto isadir (if "isdir" is TRUE, return 3)
if errorlevel 2 goto iszfile (if "iszero" is TRUE, return 2)
if errorlevel 1 goto isafile (if "exist" is TRUE, return 1)
echo %1 does not exist (last logic was FALSE, return 0)
goto quit
:isadir
echo %1 is a directory
goto quit
:iszfile
echo %1 is a null file
goto quit
:isafile
echo %1 is a normal file
goto quit
:quit
Attempts to set environment variables are intercepted and not sent
to command.com via the system call . Unfortunately, there appears to
be a defect in the MSC6.0 libraries such that putenv() and getenv()
fail. Specifically, getenv() functions properly until a putenv() is
issued, in which case the variable affected is then unavailable for
recall. Further, assuming it was already set in the environment, when
"set" is passed to command.com using "system" (which should result in
the output of all variables and their values), only the variables that
appeared in the environment before the one that was modified appear.
Examples
This command displays the value of an environment variable:
fe do echo %tmp%
This .bat file will display the values of environment variables:
@echo off
fe i ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do echo %%$i%%
Note the use of multiple %'s; to prevent substitution at the
DOS interpreter level, use %% to pass a % to fe.
Assuming this file is named "shw.bat", the syntax would be:
C> shw path tmp
c:\bat;c:\bin;c:\usr\bin;c:\dos;c:\utl
d:\tmp
Notoriously missing from DOS is a "copy" command that will copy files to
multiple disks, pausing for a disk change when the disk becomes full:
fe ( *.* ) // for all entries
? if isdir $i next // if a directory, next member
? echo $i // display name of file
? copy $i a:$i // copy to destination
? if exist a:$i next // if copy succeeded, next member
? pause // pause for disk change
? restart // restart command sequence
A more sophisticated script might detect if the file is too
big to fit on a diskette or the file is of zero size (otherwise,
an endless loop is entered), and perhaps start a command shell
to perform other tasks in response to input can be built.
Here is the same as above, on one line:
fe ( *.* ) do if d $i next ; copy $i a:$i ; if x a:$i next ; pause ; restart
Here is a batch file to do the same, only more robust:
===
@echo off
if "%debug%" == "yes" echo on
if "%2" == "" goto syntax
if not exist %1 goto nofile
if not exist %2.\nul goto nodest
fe i ( %1 ) do if d $i next ; copy $i %2$i:t ; if z $i type nul$R%2$i:t ; if x %2$i:t next ; pause ; redo
goto quit
:syntax
echo Syntax: mcopy filespec drive:[path\]
echo filespec= DOS "wildcard" pattern
echo drive= destination drive, with ":", and an optional path
echo Copy all files from filespec onto drive/path.
echo Create zero-length files, since copy does not copy those.
echo Gets into an endless loop if a file is bigger than a disk.
:nofile
echo mcopy error: no files matching %1
goto quit
:nodest
echo mcopy error: %2 is not a directory, or no trailing backslash
goto quit
:quit
===
Since DOS does not expand the wildcard on the command line to
a batch file, %1 is the filespec and %2 is the drive. The program
then attempts to copy each of the files matched in filespec to
%2$i:t (%2= drive:, $i:t= tail end of filename). Thus, this .bat
file can handle:
mcopy \usr\sound\*.wav a:
This command will generate a list of 256 " DB XXX " statements
fe i ( 000-255 ) do pipe \t DB $i >> dbdef.inc
This command will generate a file of the first 256 bytes:
fe i ( 000-255 ) do | dectohex h | tobin -o 256b.bin
List files by extension:
--- File: lext.bat ---
fe i ( %1 %2 %3 %4 %5 ) do echo $i:e | sort -u | fe j -l- do ls "*.$j"
--- End of File ---
foreach directory entry, echo the extension, and send to
sort to output the unique extensions, and send to
foreach incoming extension, list the files with that extension.
set tmp=c:\tmp
fe i ( *.* )
if exist $i\nul goto dodir
:dofile
echo $i >> %tmp%\file.lst
goto skip
:dodir
echo $i >> %tmp%\dir.lst
goto skip
:skip
set clopt=-Zi -AL -Od
fe i ( *.c )
if not exist $i:r.obj goto compile
echo $i is already compiled
goto next
:compile
cl -c %CLOPT% $i
:next
Or this batch file will copy a number of diskettes into numbered directories:
--- File: mdcopy.bat ---
@echo off
fe i ( 0-%1 ) do echo Disk # $i ; pause ; mkdir %2$i xcopy a: %2$i /s
rem Syntax: mdcopy N [name]
rem N - number of disks to copy
rem name - optional name to prepend to number
rem This program makes a series of numbered directories,
rem and copies the diskette in drive A into each directory.
rem The "name" is used, if specified.
--- End of file ---
To compile a bunch of files and copy the objects to floppy:
fe file ( *.c )
rm -f $i:r.obj
cl -c -Zi -Od $file
if not exist $file:r.obj goto error
copy $file:r.obj a:
continue
:error
echo Error during compile of $file
echo $file:r.obj was not generated
To list today's files only, this makes a good batch file:
--- ltoday.bat ---
@echo off
if "%debug%" == "yes" echo on
dt | fe i -l- do ls -l %1 %2 %3 %4 %5 $P grep $i
-- end of file --
Note: dt is another Shark program that outputs date and time
in templatic fashion, and ls is still another Shark program
that lists directory entries.
dt outputs today's date in "ls -l" format, so this fe command
executes "ls -l args" and pipes the output to "grep mm/dd/yy",
resulting in only those files with today's date. This is an
instance of using fe with only one member (the date), running
a program and piping it from with fe to another program that
uses the member piped in.
DOS Reports
While goofing around with this program and other Shark utilities,
the following abnormalities were found.
if exist a:\dir\\nul
This will return TRUE, but
copy file a:\dir\\file
will fail with "Path not found"
Caveats
The number of commands and members are fixed, and are sufficiently
large to support most scripts and member-lists (512, 2048 respectively).
This should be optimized for the different scenarios (commands from the
command line: maximum 12, no members: maximum 1). The script buffer
is fixed at 16K, but is reduced to the actual size required before
command execution begins. In that way the memory required for a simple
fe command could be reduced from >64K to the barest minimum.
fe creates or truncates a file to store the "do" command lines, which
it then removes, named in the following manner:
if FETMP is set in the environemt: %fetmp%
else if TMP is set in the environment: %tmp%\___docom.for
else .\___docom.for
When fe reads members or command input from standard input, subsequent
command shells or other programs reading from standard input fail.
Of course, the inability to redirect multiple lines to a program from
within a .bat file (as with Unix: program << here \n input ...\n here")
severely restricts the effectiveness of fe, because lengthy command
scripts necessitate the use of an additional file to hold this script.
An alternative was suggested wherein a block of lines within the .bat
file is used to supply such:
===
@echo off
...
fe -b%0 i ( %1 ) fe1
:fe1 if isdir $i echo $i is a directory
:fe1 if iszero $i echo $i is a null file
:fe1 if exist $i echo $i is a normal file
...
fe -b%0 i ( %1 ) copyunfoundfiles %2
:copyunfoundfiles if exist %1$i echo $i exists on %1
:copyunfoundfiles if ! exist %1$i copy $i %1$i
:quit
===
In this instance, the -b option indicates that fe is running
from a .bat file, and so %0 (the program name from the
command line) is searched for in the PATH, and then from
within this file, labels (lines beginning with ":") with the
name specified on the fe command line (FE1 and FE2 in this
example, where an fe script name would otherwise occur), are
searched for and read as command input (stripping off the
label identifier).
Although the above seems to be a workable approach, the
method is flawed if the searched-for .bat file is found
in a directory from which it was not expected. In order to
make it foolproof, the %0 should have substituted instead
the full pathname of the .bat file being executed; this is
still an improvement over requiring an additional script file:
fe -bc:\bat\safecopy.bat i ( %1 ) fe1
fe -bc:\bat\safecopy.bat i ( %1 ) fe2 %2
Even more unelegant is the supplying of %2 on the fe command
line, and having it interpreted in the fe script as %1. Of
course, an alternative is to provide a dummy %1 and then
refer to the %2 on the command line as %2 in the fe script.
Regardless, the approach is still under study (perhaps skipping
the %0 and instead searching back through memory blocks until
that one which spawned "fe" is found, then finding the program
name including the path and searching that file for :command
labels).
=======================================================================
fe - copyright SHARK 1991 - Programmer Bart Crane
All Rights Reserved - Distribution Encouraged
Software Provided As Is, No Warranty Express Or Implied
For More Information on SHARK, Upgrades, and other Utilities:
Shark BBS: (415) 969-6600
Mail:
SHARK
922 San Leandro Ave. Suite C
Mountain View, CA 94043
Telephone: (415) 969-3015
Fax: (415) 969-6600
Mediavision BBS:
(415) 770-0968 - Messages To: Bart Crane