Multi-OS Batch Programs

There are enough differences among the various flavors of "DOS" in real DOS, Win95, and NT4 that programs written for one often fail, sometimes for obscure reasons, in one or both of the others. The first illustration is something I used to prove a point, but also to explore some of the differences. A number of people have expressed interest in the program even though it's still (9 Feb. 1998) in beta testing (I need to *know* what breaks it) that I have decided to publish the code, comments, and explanatory material much too soon, well before I understand some of it myself. This is very preliminary stuff and will be rewritten later, when the dust settles (copyright considerations also played a role in that decision).

The program was inspired by a thread in alt.msdos.batch that began with a question about extracting the individual directory names from a fully qualified directory specification. One thing led to another, and I decided that I needed to explore the possibilities.

Several problems immediately presented themselves, one of which was that the user hadn't indicated what operating environment he was using - "Well, it shouldn't be too hard to make it work in all three." - famous last words. It was a nightmare: short vs. long names, spaces in names, different behaviors of DIR, case insensitivity, the pattern is a variable but the DIR listing is in a file - how to look for the contents of a file in a variable, list processing using the LOADFIX/DATE scheme is broken after MSDOS6.22 due to lack of LOADFIX, string processing is broken after MSDOS6.22 because of lack of the '/' switch to FOR but fixed to some extent in NT4 with extensions to FOR, and so forth, and so on. This little devil of a program is the result:

ENTER.BAT
 @echo off
 if not %pass%!==! goto %pass%
 set pass=pass2
 set count=!!
 set flag=
 set pattern=
 set realdir=
 set testdir=
 set olddircmd=%dircmd%
 set dircmd=
 set a=
 set ostype=DOS
 if %OS%!==Windows_NT! set ostype=NT
 set null=nul
 if %ostype%==NT set null=
 :loop0
 set pattern=%pattern%%1
 if %2!==! goto cont0
 set pattern=%pattern% 
 shift
 set flag="
 goto loop0
 :cont0
 if not exist %flag%%pattern%%null%%flag% goto error
 echo %pattern%> }1{.dat
 dir %flag%%pattern%*.*%flag% /a:d | find "Volume in drive" > }2{.bat
 echo set !=%%3> volume.bat
 call }2{
 set !=%!%:\
 set realdir=%!%
 :outerloop
 dir %flag%%realdir%*.*%flag% /a:d /b > }3{.dat
 echo.>> }3{.dat
 date < }3{.dat | find "En" > }4{.dat
 echo exit>> }4{.dat
 command /e:1024 < }4{.dat >> nul
 call }5{.bat
 echo %realdir%> }6{.dat
 find /i "%pattern%" }6{.dat > nul
 if not errorlevel 1 goto display
 set count=%count%!
 goto outerloop
 :pass2
 if %ostype%==NT goto nt1
 if %4!==! goto end
 goto cont11
 :nt1
 if %5!==! goto end
 :cont11
 set a=%realdir%
 set testdir=
 :innerloop
 if %ostype%==DOS set a=%a%%4
 if %ostype%==NT set a=%a%%5
 if %ostype%==DOS set testdir=%testdir%%4
 if %ostype%==NT set testdir=%testdir%%5
 shift
 if %ostype%==NT goto nt2
 if %4!==! goto cont1
 goto cont12
 :nt2
 if %5!==! goto cont1
 :cont12
 set a=%a% 
 set testdir=%testdir% 
 goto innerloop
 :cont1
 set a=%a%\
 find /i "%a%" }1{.dat > nul
 if errorlevel 1 goto end
 echo set %count%=%testdir%> }5{.bat
 echo set realdir=%a%>> }5{.bat
 goto end
 :display
 :cleanup
 set dircmd=%olddircmd%
 set maxcount=%count%
 set count=!
 echo The elements in %pattern% are
 :cleancountloop
 set %count%=
 if %count%==%maxcount% goto cleancont
 set count=%count%!
 echo echo %%%count%%%>}5{.bat
 call }5{
 set %count%=
 goto cleancountloop
 :cleancont
 set pass=
 set ostype=
 set count=
 set maxcount=
 set pattern=
 set realdir=
 set testdir=
 set a=
 set flag=
 set olddircmd=
 del }1{.dat
 del }2{.bat
 del }3{.dat
 del }4{.dat
 del }5{.bat
 del }6{.dat
 goto end
 :error
 echo.
 echo.
 echo ERROR Report: %pattern% 
 echo does not exist, lacks a trailing '\' or has some other error.
 :end

Total clarity ... sure it is. There is a commented version (about 11Kb). You should not try to retype, or even copy/paste either one because there are significant trailing spaces in some places and other places where a trailing space is a fatal error; feel free to save the files and test them, though (the usual "no commercial use" copyright license applies). If you have a problem with too little environment space, you can say COMMAND /e:1024 at the prompt to spawn a secondary command processor with a larger environment. In some cases, you may need a larger number in the /e: switch or you can add

 set pass=pass1
 command /e:2048 /c%0 %1 %2 %3 %4 %5 %6 %7 %8 %9
 goto end
 :pass1

just ahead of the set pass=pass2 line.

There are a number of personal firsts in this program, beginning with it's name: ENTER.BAT. I've used that name before in list processing, but this is the first time I've found it necessary to use it for the master file. The program is recursive - it uses the :PASS2 code to process directory entries by redirecting the list of entries into COMMAND.COM> after passing them through DATE to prefix each line with Enter (and some other garbage that gets ignored) and therefore must be invoked when the command ENTER is given. Another first was string comparison by running the pattern and the string in work through FIND in both directions: if a is in b and b is in a, then a and b are identical. Using the /i switch to FIND makes the comparisons case insensitive. But mainly, this is the first batch program I've written that is explicitly intended to work in all three "DOS" environments.

Plain text version of ENTER.BAT and Commented ENTER.BAT are available if you wish to view them or otherwise have a problem with files with the .BAT extension.


In some cases completely different programs are required. There are a several ways to deal with this:

Given that the programs here are to be of the last mentioned class, certain blocks of code will recur again and again, especially the code to detect the OS and to deal with long file names.

Detecting the OS is not a straight-forward task: VER tells us what the base OS is, but not whether we are running in a DOS box (Win3.x and Win95). Most of the time that isn't important and VER would be usable, however, to make use of VERwe have to either run it through FIND to check for key words, or import it into an environment variable - both of these require enough extra disk activity to make them undesirable if an alternative that does not require pipes is available. Unfortunately, the alternative of deducing the information from environment variables also requires pipes and FIND because some of the variables are in lower case and can be extracted only with considerable difficulty. The least inefficient procedure seems to be to look for NT first, using the OS= environment variable (very low overhead), then to look for "Windows" in the VER report if NT is not found. If it isn't NT, and "Windows" is not in the report, we will assume MSDOS. This ignores OS/2 and other non-Microsoft operating systems.

It's time for an aside:
I wrote this book not because I like the MS operating systems and their batch languages, but because I detest them - they are terrible operating systems with brain damaged scripting languages. NT is the least bad, but it's still a long way from what I would consider really usable. This book grew out of my need to find ways to get the job done despite Microsoft's best efforts to prevent me from doing whatever need doing. OS/2 is omitted because it is not a Microsoft operating system and I am not forced to deal with it.

Back to detecting the OS:

set this_os=DOS
if %OS%!==! goto try95
set this_os=NT
goto os_ok
:try95
ver | find "Wi" > nul
if not errorlevel 1 set this_os=WIN
:os_ok
will, in the majority of cases suffice to tell our code which block of commands to use. Since I know nothing about Win98 or NT5 at this time, I can only assume that they will not introduce additional breakage requiring additional testing.

Rule (0) for the following examples: Only real DOS, and DOS boxes in Win31, Win95, and NT4 are provided for, and then only in fairly simple cases

Long file names introduce several problems that are intractable: present or absent quotes, and batch file delimiters in file names are the most important. These interact: if

 WHATARGS.BAT
@echo %1!%2
is given under Win95
"foo=bar"
as an argument, it reports
"foo=bar"!
but, if it is given
foo=bar
it reports
foo!bar
Similarly, it reports spaces correctly is the string is quoted, but not if it isn't. From this simple experiment, it is clear that the proper way to handle file names is to require that long names be quoted and short names unquoted when passed as arguments. It is important to remember that real DOS barfs if file names are quoted when passed to functions such as DIR - this is the reason for passing short names (the only kind of names in real DOS) unquoted, though it makes no difference for short names and long names not containing delimiters in Win95 and NT. If it is necessary to pass long names unquoted, then code like that in the first example in this section will be necessary, along with the implicit assumption that the file names contain no commas, semicolons, equals signs, or clusters of spaces with or without other delimiters because the code can replace only delimiters it knows about in advance and that are hard coded in the program.

Rule (1) for the following examples: Long file names are quoted when passed to a batch file as an argument; short file names are never quoted.

Let's see what applying that preceding stream-of-consciousness stuff can do when applied to some real word code.

A few days ago I responded to a user's question about extracting the base name from a long file name (unspecified OS, but I correctly deduced it was Win95 from the header of his usenet message) with this:

 @echo off
 if %1!==}{! goto pass2
 set this=%0
 md }{
 set original=
 :loop
 set original=%original%%1
 shift
 if %1!==! goto cont
 REM following line ends with exactly one space
 set original=%original% 
 goto loop
 :cont
 copy "%original%" }{
 for %%a in (}{\*.*) do %this% }{ %%a
 goto end
 :pass2
 ren %2 *
 dir }{\*.* /b > }{.dat
 echo. >> }{.dat
 set longname=
 date < }{.dat | find "En" > }{.bat
 echo :loop> enter.bat
 echo set longname=%%longname%%%%4>> enter.bat
 echo shift>> enter.bat
 echo if %%4!==! goto end >> enter.bat
 echo set longname=%%longname%% >> enter.bat
 echo goto loop>> enter.bat
 echo :end>> enter.bat
 call }{
 deltree /y }{
 del }{.bat
 del }{.dat
 del enter.bat
 set this=
 echo The long name of "%original%" without the extension is "%longname%"
 set original=
 set longname=
 :end
That code doesn't work in any other environment: real DOS doesn't like the quotes, and NT barfs on the syntax. The basic code copies the given file to an empty directory and renames all the files in that directory to * to strip the extension. That is an old DOS trick, but it doesn't work with long file names containing dots in either Win95 or NT4 - it truncates at the first dot instead of the last. I used the Win95 specific behavior of FOR to get the short name (FOR %%a in ( *.* ) returns the short names of every file in the directory - since there was only one, it returns it). It was necessary to omit the usual CALL from the DO clause in order to avoid having FOR return the new file name as well.

The standard DOS code can be modified somewhat to reduce disk usage

@echo off
md }{
rem> }{\%1
ren }{\%1 *
dir }{\*.* /b > }{.dat
echo. >> }{.dat
date < }{.dat | find "En" > }{.bat
set basename=
echo set basename=%%4> Enter.bat
call }{
deltree /y }{ > nul
for %%a in (enter.bat }{.bat }{.dat) do del %%a
echo %basename%
That provides a module for getting base names in DOS and Win3.1. It can be made to work under Win95 as well as real DOS and Win3.1 by using the FOR trick mentioned above:
@echo off
if %1!==}{! goto pass2
md }{
rem> }{\%1
for %%a in ( }{\*.* ) do %0 }{ %%a
:pass2
ren }{\%1 *
dir }{\*.* /b > }{.dat
echo. >> }{.dat
date < }{.dat | find "En" > }{.bat
set basename=
echo set basename=%%4> Enter.bat
call }{
deltree /y }{ > nul
for %%a in (enter.bat }{.bat }{.dat) do del %%a
echo %basename%

Note that DELTREE doesn't come with NT4 - the above programs fail unless it is present because it is left over from an earlier operating system to which NT4 was an upgrade, or is provided some other way (in a networked directory on a WfW or Win95 machine in the PATH, for example).




One user asked for a program that would provide a list of directories and their sizes - this provided me with an opportunity to extend the above multi-OS thinking into list processing: it required a bit of string processing and directory listings for each directory in a DIR /s listing. It brought up an additional point: you can't use syntax like echo set %%quote%%=">> enter.bat because the quote mark will inhibit the >>. For the fully commented version of this, see commented.dirsize.bat.html

 @echo off
 dir %1 /a:d /b /s > }{.dat
 echo.>> }{.dat
 date < }{.dat | find "Enter " > }{.src
 echo exit>> }{.src
 set arg=4
 set sw=
 set mark="
 set e=/e:1024
 if %os%!==Windows_NT! set arg=5
 if %os%!==Windows_NT! set sw=/x
 if %os%!==Windows_NT! set e=
 echo @echo off> enter.bat
 echo if %%%arg%!==! goto end>> enter.bat
 echo set quote=>> enter.bat
 echo set dname=>> enter.bat
 echo :loop>> enter.bat
 echo set dname=%%dname%%%%%arg%>> enter.bat
 echo shift>> enter.bat
 echo if %%%arg%!==! goto cont>> enter.bat
 :: Note that there is a space following %%dname%% in the following line
 echo set dname=%%dname%% >>enter.bat
 echo set quote=%%mark%%>> enter.bat
 echo goto loop>> enter.bat
 echo :cont>>enter.bat
 echo echo %%dname%% (size in bytes)>> enter.bat
 echo if exist %%quote%%%%dname%%\*.*%%quote%% dir %sw% %%quote%%%%dname%%%%quote%%>> enter.bat
 echo if not exist %%quote%%%%dname%%\*.*%%quote%% echo          0 file(s)              0 bytes>> enter.bat
 echo :end>> enter.bat
 %comspec% %e% < }{.src | find " bytes" | find /v " free">result.txt
 del }{.dat
 del }{.src
 del enter.bat
 set sw=
 set arg=
 set e=
 set mark=

This approach to list processing is based on the LOADFIX/DATE approach analysed in List Processing but redirects the preprocessed list to the input of the command processor (COMMAND.COM (DOS and Win95) or CMD.EXE (NT4) so that the ENTER command (provided here by ENTER.BAT) is invoked once for each line in the file. Note that it is necessary to append an EXIT command to the end of the file, or the command processor will never terminate and the batch program will hang.


One category of FAQ involves doing something in, to, or for every directory, every directory matching a wildcard pattern, every file, or every file matching a wildcard pattern. Since the code is so similar for all of those, I'll treat them together. Of course, the procedures for each individual operating system are much simpler than any of this code, and are almost trivial for NT, but users seldom specify which operating system they want code for, or they may need it for two or all three.
These kinds of questions require the functionality that is usually associated with a SWEEP utility - the task is to write one in batch language that works in all three operating systems. The previous topic presents code that is most of the way there - in fact it incorporates a special purpose version of the general code we want here.
This code is largely the same as that above - the differences are The syntax for calling this version of SWEEP.BAT is
   SWEEP [directory [file]]
where directory is any valid directory specification, including nothing at all (for the default directory) and file is any valid file specification that does not end with a backslash, including nothing at all, which turns off file scanning. Note that if a file specification is used, the directory specification must also be used because there is no way to tell the difference between a file specification and some allowed forms of directory specification - there is no way to specify files in the default directory, the default directory must be specified, though it can be specified with just a dot. Wildcards are allowed in both the directory and file specifications provided that they are valid for the operating system under which the program is run (in my test directory, *p.bat returns only SWEEP.BAT, because that is the only file having a name ending in p and a .bat extension on Win95 and NT4 systems, but all the batch files on the MSDOS 6.22 system.
When considering the first few lines of this code, remember that you can't use redirection in an IF command because the output (nothing) of the IF command is what would be redirected; commands having redirection must not be parts of other commands - they must be on lines by themselves.
 @echo off
 if not %2!==! goto cont0
 dir %1 /a:d /b /s > }{.dat
 goto cont1
 :cont0
 if not %2!==! dir %1\%2 /b /s > }{.dat
 :cont1
 echo.>> }{.dat
 date < }{.dat | find "Enter " > }{.src
 echo exit>> }{.src
 set arg=4
 set sw=
 set mark="
 set e=/e:1024
 if %os%!==Windows_NT! set arg=5
 if %os%!==Windows_NT! set sw=/x
 if %os%!==Windows_NT! set e=
 echo @echo off> enter.bat
 echo if %%%arg%!==! goto end>> enter.bat
 echo set quote=>> enter.bat
 echo set dname=>> enter.bat
 echo :loop>> enter.bat
 echo set dname=%%dname%%%%%arg%>> enter.bat
 echo shift>> enter.bat
 echo if %%%arg%!==! goto cont>> enter.bat
 :: Note that there is a space following %%dname%% in the following line
 echo set dname=%%dname%% >>enter.bat
 echo set quote=%%mark%%>> enter.bat
 echo goto loop>> enter.bat
 echo :cont>>enter.bat
 echo set thisitem=%%quote%%%%dname%%%%quote%%>> enter.bat
 echo call }user{>> enter.bat 
 echo :end>> enter.bat
 %comspec% %e% < }{.src > nul
 if exist }return{.bat call }return{
 if exist }return{.bat del }return{.bat
 del }{.dat
 del }{.src
 del enter.bat
 set sw=
 set arg=
 set e=
 set mark=
While the program can be incorporated into another batch file with no difficulty, the example is designed to be CALLed from another batch program. Note that it cannot write }USER{.BAT, which contains the program to be executed once for each item in the list generated by the SWEEP program because this would require redirecting redirection characters. }USER{.BAT must be prepared separately.

}USER{.BAT can do anything that a batch file can do inside a secondary command processor, including writing another batch file that is to be CALLed when the secondary command processor terminates. This auxiliary batch (}RETURN{.BAT) file runs at the same level as the wrapper batch file and SWEEP and can do anything a batch file can do. It is important that it not unconditionally transfer control away from SWEEP - it must return in order that SWEEP can clean up the mess it made. }RETURN{.BAT is considered transient and is deleted by SWEEP. }USER{.BAT is not considered transient and is not deleted by SWEEP. If SWEEP is used as presented, it should always be CALLed by the program that uses it so that it will return and allow that program to continue and clean up its transient debris.

Now for some example code. The first two examples are the test programs I used while developing SWEEP. They simply list the directories and files they process. These are to be prepared in advance and used from the command line without an overall wrapper, though one can be used. The first one lists all the directories that match its given pattern (remember to quote the pattern if it contains spaces); the second lists all the files that match its file pattern in the directories that match its directory pattern. In both these examples, the list is written after }USER{.BAT has been invoked for the last item.

Test syntax:
  sweep
to list all the subdirectories in the default directory. }USER{.BAT
@echo off
echo echo This is a directory: %thisitem%>> }return{.bat
Test syntax:
  sweep . *.bat
to list all the batch files in all the subdirectories in the default directory. }USER{.BAT
@echo off
echo echo This is a batch file: %thisitem%>> }return{.bat
If those work, and they do, then everything else that involves only valid commands and file/directory specifications should also work. To see, let's examine a couple of real-world problems. These were taken from alt.msdos.batch on adjacent days. In the first, we will illustrate CALLing SWEEP.BAT and in the second, the code will be incorporated into the master program. Where the user specified the C: drive, I have changed the code to use my test RAMDRIVE (I'm not fool enough to test experimental code that has teeth like these on my main HDD). I created fake directory structures with dummy files on the RAMDRIVE to simulate a real-world configuration. The RAMDRIVE lives on the MSDOS/WfW3.11 system, but is accessible by all my systems, so I use it for safe testing.

The first is (paraphrased) "How do I get the fully qualified filespec of a file I know just the name of and that it's somewhere on my HDD into an environment variable, and no, I won't tell you what operating system I want this for?". Obviously there are complications, especially if the filename is not unique on the drive. The simple case is almost trivial: just capture the output of DIR foo /s /b and deal with any spaces while putting it into the environment - twenty lines or so. Dealing with the possibility of multiple files requires considerably more sophistication. }USER{.BAT must write a }RETURN{.BAT that deals with an unknown number of filespecs, and therefore an unknown number of environment variables. We'll use a bang counter to name the variables. We have to do the initialization code for the bang counter before calling SWEEP. This is the wrapper file - it can be called anything that is a valid .BAT filename (it does not work correctly under NT4 if it has a .CMD extension) - lets call it FINDFILE.BAT:
 @echo off
 if %2!==! goto end
 set count=!
 call sweep %1 %2
 if %count%==! goto error
 set last=%count%
 set count=!
 :loop
 if %count%==%last% goto end
 echo echo A copy of %2 was found as %%%count%%%> }{.bat
 echo set  %%count%%=>> }{.bat
 call }{.bat
 set count=%count%!
 del }{.bat
 goto loop
 :error
 echo %2 was not found anywhere in %1 or its subdirectories
 :end
 set %count%=
 set count=
 set last=
and this is }USER.BAT{
 @echo off
 echo set %%count%%=%thisitem%>> }return{.bat
 echo set count=%%count%%!>> }return{.bat
The calling syntax is the same as for SWEEP: the file name followed by the directory to begin searching in and then the pattern for the file(s) to be found - if the program is FINDFILE.BAT, the root of the C: drive is the starting point, and the program is to find TEST.BAT then the syntax is findfile c: test.bat - remember to quote names with spaces in them. The path argument (the first one) must not end with a backslash.
That example displays the fully qualified long filenames on the screen, but then deletes the environment entries containing the filenames. If you want to preserve that information (and delete it manually later) then comment out the lines
echo set  %%count%%=>> }{.bat
and
set %count%=
The other example is in response to a code to move all files of a specific type from wherever they are on the HDD to a specific directory. One respondent suggested MOVE /s, which would be great, except that MOVE doesn't accept a /s switch. This batch program implements that functionality.
The complications are, as above, there may be multiple copies of the file or multiple files with the same name, that the files in the target directory should be ignored, and that there may be a preexisting file of the same name in the target directory. Duplicate files will be overwritten in Win95 and real DOS, and will be left in place in NT4 (a message will be displayed). The target directory will be removed from the list during processing. The syntax will require three arguments: the starting directory, the file pattern and the target directory, which must be specified as a fully qualified directory specification, quoted if it contains spaces (DO NOT quote it unless it contains at least one space - looking for the space is the only way to tell if it is quoted). Note that if you want to move .BAT files, this program and all its components must already be in the target directory and must be run from there. Note that because of the simple method used to exempt the target directory, the target directory and all its subdirectories are removed from the list - it is not possible to use this program to move files from subdirectories to a parent directory unless the exemption code is remarked out or removed, and the target directory or one of its subdirectories is made the starting point. This example includes the SWEEP code as part of itself. Much of the overall code is the same as in the previous example. Since nothing need be done to the root environment, there is no }RETURN{.BAT file generated or used.

}USER{.BAT
 @echo off
 if %thisitem%!==! goto end
 set flag=/y
 if %os%!==Windows_NT! set flag=
 move %thisitem% %target%
 :end
MOVE.SLASH.S.BAT (name it something 8.3 for real DOS)
 @echo off
 if %3!==! goto end
 set target=%3
 echo %3> }}{{.dat
 find " " }}{{.dat > nul
 if errorlevel 1 set target="%3"
 dir %1\%2 /b /s > }{.dat
 echo.>> }{.dat
 date < }{.dat | find "Enter " > }}{{.dat
 find /i /v %target% < }}{{.dat > }{.src
 echo exit>> }{.src
 set arg=4
 set sw=
 set mark="
 set e=/e:1024
 if %os%!==Windows_NT! set arg=5
 if %os%!==Windows_NT! set sw=/x
 if %os%!==Windows_NT! set e=
 echo @echo off> enter.bat
 echo if %%%arg%!==! goto end>> enter.bat
 echo set quote=>> enter.bat
 echo set dname=>> enter.bat
 echo :loop>> enter.bat
 echo set dname=%%dname%%%%%arg%>> enter.bat
 echo shift>> enter.bat
 echo if %%%arg%!==! goto cont>> enter.bat
 :: Note that there is a space following %%dname%% in the following line
 echo set dname=%%dname%% >>enter.bat
 echo set quote=%%mark%%>> enter.bat
 echo goto loop>> enter.bat
 echo :cont>> enter.bat
 echo set thisitem=%%quote%%%%dname%%%%quote%%>> enter.bat
 echo call }user{>> enter.bat 
 echo :end>> enter.bat
 %comspec% %e% < }{.src > nul
 del }{.dat
 del }{.src
 del enter.bat
 set sw=
 set arg=
 set e=
 set mark=
 :end
In case you think this stuff is easy to write, think again - the material from SWEEP to here represents about eight hours of work. Much of it trying to find commands that will work in all three operating systems. On example is the approach to removing the target directory in the last example: putting the FIND in }USER{.BAT simply didn't work - the idea was to put the THISITEM data in a file and compare that to TARGET using FIND, then test the ERRORLEVEL - worked fine in Win95 and real DOS, but prevented NT4 from processing more than the first line in the list. There were many other things like that. This sort of multiple OS batch code must be considered fragile.
 

Simpler Stuff, Elements, and Primatives

One very common FAQ is "How do I get the date into an environment variable?" Occasionally the operating system will be mentioned, but usually it isn't. This code is universal: it works in real DOS, Win3.x, Win9.x, and NT4.
 @echo off
 set field=3
 set key=Current
 if %OS%!==Windows_NT! set field=4
 if %OS%!==Windows_NT! set key=The
 echo. | date | find "%key%" > }{.bat
 echo shift> %key%.bat
 echo set xdate=%%%field% >> %key%.bat
 call }{
 echo. | time | find "%key%" > }{.bat
 echo set xtime=%%%field% > %key%.bat
 call }{
 del %key%.bat
 del }{.bat
 set field=
 set key=
 echo %xdate% %xtime%
This approach is probably language version specific - that code is for the US English versions (all I have access to).
The formats of the lines (on my home systems) we need from the date and time responses from the various operating sytems are
NT DATE
The current date is: day_name mm-dd-yyyy
All others
Current date is: day_name mm-dd-yyyy
NT Time
The current time is
All others
Current time is: hh:mm:ss.xxa/p
As you can see, each of the NT responses has a different number of fields and a different first field from the responses from the other operating systems. The conventional approach to putting the date into an environment variable requires hard coding the text of the first field and the number of fields. This approach assumes that the first field and target field number are consistent within operating sytems and that the DATE response has one more field to discard than that of TIME.
The process is
  ** Copyright 1998, Ted Davis - all rights reserved ** 

Input and feedback from readers are welcome. NOTE: the subject of the message must contain the word "batch" for the message to get past the spam filter.

Back to the Table of Contents page

Back to my personal links page - back to my home page