Getting Console or Disk Data into Environment Variables
under MS-DOS and Windows

5th edition by Eric Pement <pemente@northpark.edu>
Oct. 15, 2002 (answers rearranged, many new things added)

Since this file was first developed in 1998, I have found nearly a dozen different ways to address this problem. What began as a one- or two-page response has increased with each version. This 5th edition is a vast rearrangement over the previous versions.

The task is to get strings either (a) typed at the keyboard, or (b) printed to the screen, or (c) residing in a diskfile, and put those strings into an environment variable. The operating system is MS-DOS or Windows or maybe Windows 2000/WinNT.

I list the solutions in order of ease-of-use (my subjective opinion). My personal favorite is #1, since I'm a licensed user of 4DOS. If I couldn't use 4DOS, my next choice would be #2, an external utility dedicated to this task. I list sed and awk as a separate solution (#3), even though they are also "external utilities", simply because I know a lot about them and because they are extremely safe. (In other words, they've been around for many years, you can get the source code, and the main distribution points are known to be virus-free, if that's a concern.)

If you are unable or unwilling to install third-party software on your DOS or Windows computer, your alternative is to select one of six different solutions that best fits your needs from #4.

Select one of the following methods:
  1. Use 4DOS by JP Software (replaces COMMAND.COM)
  2. Use one of several free, external utilities made for this task
    Plus: Making it work under Windows NT
  3. Use sed or awk (widely available freeware)
  4. Solutions that use pure MS-DOS only:
    1. Embed a single linefeed in the batch file
    2. Prompt the user to type a line
    3. Use DEBUG to create a temporary file
    4. Use ECHO to create intermediate file
    5. Get first word of a textfile into a variable
    6. Get first line of a textfile into a variable

I would be remiss if I did not give credit to several people who have been invaluable in providing key solutions over the years. These people include: Tom Lavedas, Ted Davis, "Outsider", Benny Pederson, John Savage, Herbert Kleebauer, Gerard Piette, and Timo Salmi. If I have forgotten to credit anyone else, please let me know and I'll remedy the omission.


METHOD 1 (uses 4DOS or 4NT)

Under 4DOS, getting data into environment variables is simple. 4DOS is a commmand interpreter (shell) replacement for COMMAND.COM. It is commercial software, written by JP Software, so this solution requires that you have paid a license for 4DOS, 4NT, or "Take Command" (the current single-user cost is about $70). However, to me the numerous advantages of 4DOS are worth parying for. 4NT is preferred for users of Windows NT and Windows 2000.

   echo 1234 | input %%myvar             ; puts "1234" into %myvar%
   set myvar=%@line[MYFILE,5]            ; puts line 6 into %myvar%
   set myfar=%@word[4,%@line[MYFILE,6]]  ; puts 5th word of line 7 into %myvar%

The only notable thing about this syntax is that words and lines are numbered beginning with 0, not 1. Thus the desired word and line number should be decremented by 1 when passing the value to the 4DOS or 4NT %@line[] function. 4DOS also permits words to be pulled from the right end of a line, as well.


METHOD 2 (uses freeware, dedicated programs)

For those who prefer freeware solutions and don't need/want the immense power offered by 4DOS/4NT, here is the easiest solution for most people. It uses separate utilities, such as STRINGS or ASET, to directly create the environment variables. These utilities permit a variety of string manipulation, as well as math functions.

For MS-DOS or Windows 98 (and earlier versions)

If you run Windows NT, Win2000, or WinXP, click here.

I recommend STRINGS v2.5 by Douglas Boling (PC Magazine) and ASET v1.0 by Richard Breuer because they are freeware and are easily available on the Internet. STRINGS comes with ASM source code included. Consider these four examples of obtaining console output:

  echo Greetings!            # prints "Greetings!" to screen
  wc -l < myfile             # prints "1234" to screen
  echo. | date | find "199"  # prints "Current date is Thu 12-17-1998"
  calc 7 + 33                # prints "40" to screen

You will find that STRINGS and ASET easily put these into variables:

  echo Greetings! | STRINGS hi=ASK     # puts "Greetings!" into %hi%
  wc -l < myfile |  STRINGS num=ASK    # puts "1234" into %num%
  STRINGS hi=LEFT Greetings!,10        # puts "Greetings!" into %hi%
  STRINGS today=date                   # uses internal date function
  STRINGS now=time                     # uses internal time function
  STRINGS sum=ADD 7,33                 # uses internal math function
  calc 7 + 33 | STRINGS sum=ASK        # or use calc to create %sum%

  echo Greetings! | ASET hi=line       # puts "Greetings!" into %hi%
  wc -l < myfile | ASET num=line       # puts "1234" into %num%
  ASET hi='Greetings!'                 # puts "Greetings!" into %hi%
  ASET today=date                      # uses internal date function
  ASET now=time                        # uses internal time function
  ASET sum=7+33                        # uses internal math function
  calc 7 + 33 | ASET sum=line          # or use calc to create %sum%

If your data exists on disk, both STRINGS and ASET are able to access diskfiles on a line-oriented basis. For example:

  STRINGS var=read MYFILE,3       # put line 3 of MYFILE into %var%
  ASET var=LINE(3,'MYFILE')       # put line 3 of MYFILE into %var%

If you want to prompt the user for a string of words or letters, and then put that string in a variable, both STRINGS and ASET can do that easily. ASET's getstr() function will also permit cursor movement foreward and backward, including insert and delete, before pressing the RETURN key. These examples should illustrate:

  Sample STRINGS usage:                        Sample ASET usage:
  @echo off                                    @echo off
  strings var=ask Enter your full name:        echo Enter your full name:
  echo The user typed /%var/.                  aset var=line
                                               echo The user typed /%var/.
  Advanced STRINGS features:
  @echo off
  ::   variable length a max of 20 chars, "1" means mask chars with asterisks
  strings var=ask Enter your password: ,20,1
  echo The password is :%var:

  Advanced ASET features:
  @echo off
  :: use CLS to move the prompt to line 1
  cls
  echo Enter your password:
  ::   args are (max-length,'default string',row,column)
  aset var=getstr(20,'joshua',1,21)
  echo.
  echo The password is :%var:

Both STRINGS and ASET have a wide range of functions to generate data on time, date, math, file, disk, memory, and other values, and to transform or parse strings (lowercase, uppercase, substrings, count words, etc.). They are extremely flexible, not too large (14k and 100k respectively), and are free of charge.

  STRINGS v2.5
  ftp://ftp.zdnet.com/pcmag/1992/1222/strings.zip (filesize: 75k)
  strings.zip (local disk copy)
  
  ASET v1.0
  ftp://ftp.uwasa.fi/pc/batchutil/aset10.zip (filesize: 80k)
  ftp://ftp.simtel.net/pub/simtelnet/msdos/batchutl/aset10.zip

Making it work under Windows NT and Windows 2000

STRINGS and ASET (and most other environment manipulation utilities) do not work under Windows NT and Windows 2000, even though they work as advertised in a DOS session or a DOS window under Microsoft Windows 9x. Why is this, and can it be corrected?

Last question first: No, the problem cannot be corrected. Though Windows 2000 may complain "not enough environment space" when running STRINGS or ASET, the problem is not due to insufficient environment space. The problem is caused by the fact that STRINGS and ASET both use the DOS interrupt call INT 21 to alter environment variables. Windows NT and Windows 2000 are incompatible with this common technique. Here are some alternate solutions:

Windows 2000: Get input from keyboard

To prompt the user for a value and then put their keyboard reply into an environment variable, run this command:

   SET /P VARNAME=Please enter your name:

SET will display the prompt "Please enter your name:" to the user, who is expected to type a string of lettes and press ENTER. Whatever they type will be stored in the variable %VARNAME, where it can be retrieved for later operations.

Windows NT: Get input from keyboard

This technique doesn't work with Windows NT. However, Simon Sheppard (www.ss64.com) wrote this script using Windows Scripting Host (present on NT and Win2K machines) to store user input into an environment variable:

   :: Input1.cmd - A routine to prompt the user for an input string.
   :: Requires WSH version 1.0 or later.
   :: Input string is stored in the variable v_input
   :: Use optional command line argument UCASE to convert input to all uppercase.

   :: usage:
   :: input1
   :: input1 ucase

   @ECHO off
   SETLOCAL
   SET v_vbs=%TEMP%\~tmp.VBS
   SET v_cmd=%TEMP%\~tmp.cmd

   ECHO Set oFS=CreateObject("Scripting.FileSystemObject")>%v_vbs%
   ECHO oFS.OpenTextFile("CON",2).Write "Enter a string: ">>%v_vbs%
   ECHO S=%1(Trim(oFS.OpenTextFile("CON",1).Readline))>>%v_vbs%

   ECHO oFS.CreateTextFile("%v_cmd%",2).Write "set v_input=">>%v_vbs%
   ECHO oFS.OpenTextFile("%v_cmd%",8).Write S>>%v_vbs%

   cscript.exe //nologo %v_vbs%
   CALL %v_cmd%

   DEL %v_vbs%
   DEL %v_cmd%

   SET v_input
   ENDLOCAL & SET v_input=%v_input%

One workaround is to place the command(s) to these utilities in the file called C:\WINNT\AUTOEXEC.NT or C:\%WINDIR%\AUTOEXEC.NT. The file AUTOEXEC.NT is a "batch" file and it runs like AUTOEXEC.BAT does in normal MS-DOS. If you are able, execute ASET or STRINGS from within AUTOEXEC.NT. Every time CMD.EXE or COMMAND.COM is executed, AUTOEXEC.NT will be executed, and any variables which are set there will persist for the life of the CMD or COMMAND window.

There's probably another workaround, but I don't know what it is right now. If someone else does, please e-mail me. Thanks!


METHOD 3 (uses sed or awk)

This method does not require a prepared file like PREFIX.DAT, above. However, it does need an external string manipulation program like sed (stream editor) or awk, which are available as freeware for MS-DOS.

 sed15/DOS    ftp://ftp.simtel.net/pub/simtelnet/msdos/txtutl/sed15x.zip
 sed15/Win95  http://www.cornerstonemag.com/sed/sed15exe.zip
 gsed 3.02.80 http://www.student.northpark.edu/pemente/sed/sed3028a.zip
 GNU awk/DOS  ftp://ftp.simtel.net/pub/simtelnet/gnu/gnuish/gawk306x.zip

Because sed is fairly small (22k for sed15, 84k for gsed) as compared to awk (226k), I often prefer to use sed.

Wherever our data comes from, we must be able to prepend "set value=" before the data. If the term is "Jan. 1, 2003", we must be able to change it to "set value=Jan. 1, 2003". Sed or awk are superb at doing this.

In Example 1, we'll use console output and sed to put some data into a variable. In Example 2, we'll get the data from disk and use awk to put the data into a variable. Both techniques use a DOS batch file.

Example 1: Get today's date and put it into a variable, %DATE%

  @echo off
  :: The output of 'date' in Windows 98 looks like this:
  ::   Current date is Thu 04-11-2002
  ::   Enter new date (mm-dd-yy):
  echo. | date | sed "/2002/!d; s/.* /set date=/" >tmp_.bat
  ::
  call tmp_.bat
  echo Today's date is: [%DATE%]
  ::
  :: after processing, delete temp file quietly, unset the variable
  del tmp_.bat >NUL
  set date=

Example 2: Get John Doe's phone number from FOO.DAT, and put it into the variable %PHONE%

  @echo off
  ::  Look for name John Doe, get field #4
  awk "/John Doe/ {print \"set phone=\" $4}" FOO.DAT >tmp_.bat
  call tmp_.bat
  echo John Doe's phone number is /%PHONE%/
  ::
  del tmp_.bat >NUL
  set phone=

Of course, in situations like Example 2, you must write your sed or awk script to ensure that you don't end up with more than one line of data (and, optionally, that the total line length is under 127 characters).

Example 3: Prompt the user for a phrase and put it into the variable called %phr%

  @echo off
  echo Enter a phrase and press the ENTER key:
  awk "{print \"set phr=\" $0;exit;}" >tmp_.bat
  call tmp_.bat
  echo The line of words typed is "%phr%"
  del tmp_.bat >NUL
  set phr=

METHOD 4 (several DOS-only solutions):

Two things are needed: your data directed to disk and a batch file.

First, if your data will come from console output (such as the screen output of ECHO, GREP, SED, WC, DATE, CALC, FIND, etc.), you must redirect the data to a disk file. The data must be one line only! For example:

     echo Some sample data           > ANSWER.DAT
     grep "pattern" MYFILE.TXT       > ANSWER.DAT
     sed -n "/regexp/p" MYFILE.TXT   > ANSWER.DAT
     wc -l < MYFILE.TXT              > ANSWER.DAT
     echo. | DATE | find "199"       > ANSWER.DAT
     calc 87 * 55                    > ANSWER.DAT
     find "this string" < MYFILE.TXT > ANSWER.DAT

However you obtain your data (sed, wc, calc, etc.), the point is that the data may not be longer than one line. In fact, since MS-DOS cannot handle command lines longer than 127 characters, ANSWER.DAT must be several characters shorter than that. (Technically, 127 minus the length of the string "set your_variable_name=", which will be prepended to ANSWER.DAT later on.)

Second, in the batch file we need to be able to issue the command

      set MYVAR={the contents of ANSWER.DAT go here}

This is a difficult task, since MS-DOS doesn't offer an easy way to prepend "set MYVAR=" to a file. There are at least six different solutions available under MS-DOS without resorting to third-party utilities (even though using a third-party program is the easiest solution). Technically, there are two others that I am omitting here because, in my opinion, they are more obtuse or difficult to use than the ones listed below. If you know of any DOS-only solutions I haven't remembered, please let me know. Thanks!

Solution (a): Embed a single linefeed in the batch file.

Normal DOS text files and batch files end all lines with two consecutive bytes: a carriage return (Ctrl-M, hex 0D, or ASCII 13) and a linefeed (Ctrl-J, hex 0A or ASCII 10). In the batch file, you must be able to embed a Ctrl-J in the middle of a line.

Many text editors have a way to do this: via a Ctrl-P followed by Ctrl-J (DOS EDIT with Win95/98, VDE), via a Ctrl-Q prefix (Emacs, PFE), via direct entry with ALT and the numeric keypad (QEdit, Multi-Edit), or via a designated function key (Boxer). Other editors absolutely will not support this (Notepad, Editpad, EDIT from MS-DOS 6.22 or earlier; VIM can insert a linefeed only in binary mode, but not in its normal text mode).

If you can do it, your batch file might look like this:

     @echo off
     :: assume that the datafile exists already in ANSWER.DAT
     echo set myvar=^J | find "set" >PREFIX.DAT
     copy PREFIX.DAT+ANSWER.DAT  VARIAB.BAT
     call VARIAB.BAT
     echo Success! The value of myvar is: [%myvar%].
     :: erase temp files ...
     for %%f in (PREFIX.DAT ANSWER.DAT VARIAB.BAT) do del %%f >NUL

Where you see the ^J on line 3 above, the linefeed should be embedded at that point. Your editor may display it as a square box with an embedded circle.

The drawback to this method is that some e-mail or Usenet programs automatically convert lone Ctrl-J characters to normal 2-byte line endings, so your batch files may not survive well over the Net.

Solution (b): Prompt the user to type a line.

This solution doesn't require any special text editor, but does require user assistance in making the batch file.

     @echo off
     :: assume that the datafile exists already in ANSWER.DAT
     echo.
     echo Type the words "set myvar=" (don't type the quote marks)
     echo and then immediately after the = sign, press Control-Z!
     copy con PREFIX.DAT
     copy PREFIX.DAT+ANSWER.DAT  VARIAB.BAT
     call VARIAB.BAT
     echo Success! The value of myvar is: [%myvar%].
     :: erase temp files ...
     for %%f in (PREFIX.DAT ANSWER.DAT VARIAB.BAT) do del %%f >NUL

Note that this batch file cannot run unattended and that the user must manually create the PREFIX.DAT file on-the-fly. Do not press the ENTER key before pressing Control-Z.

Solution (c): Use DEBUG to create a temporary file.

The following solution requires no user intervention, nor does it require single linefeeds in a DOS batch file. DEBUG.EXE is included in all standard distributions of MS-DOS and is in Windows 95/98 in C:\WINDOWS\COMMAND, so you can use it unless someone has deleted it.

     @echo off
     :: assume that the datafile exists already in ANSWER.DAT
     echo e 100 "set myvar="             > TEMP.FIL
     echo n PREFIX.DAT                  >> TEMP.FIL
     for %%i in (rcx a w q) do echo %%i >> TEMP.FIL
     debug < TEMP.FIL
     copy PREFIX.DAT+ANSWER.DAT  VARIAB.BAT
     call VARIAB.BAT
     echo Success! The value of myvar is: [%myvar%].
     :: erase temp files ...
     for %%f in (PREFIX.DAT ANSWER.DAT VARIAB.BAT TEMP.FIL) do del %%f >NUL

Many people are skittish about using DEBUG and rightfully so, since DEBUG can crash a hard drive or delete files and directories. Therefore, here is an explanation of what the previous commands actually do. I obtained these commands from Dan Gookin's Guide to Underground DOS 6.0 (Bantam Books, 1993), pp. 187-190, which tells quite a lot about using DEBUG. For the cautious user, here's what these commands mean to DEBUG:

     e 100 "set myvar=" ; at base address 100, Enter this "string"
     n PREFIX.DAT       ; "n" means set a filename called PREFIX.DAT
     rcx                ; in Register CX, set the size of the file
     a                  ; filesize A hex (10 bytes) put in register CX
     w                  ; Write the file set by "n", i.e., PREFIX.DAT
     q                  ; Quit DEBUG

Solution (d): Use ECHO to create an intermediate file

(To be written)

Solution (e): Get first word of a textfile into a variable

(To be written)

Solution (f): Get first line of a textfile into a variable

(To be written)

Warning! In all these methods, note that they use temporary files (ANSWER.DAT, PREFIX.DAT, VARIAB.BAT, and TEMP.FIL). We have assumed that files with these names don't already exist on disk. If they do exist, the batch file overwrites them without asking permission. If these filenames might conflict with files on your computer, change them to a filename not likely to be used, such as "#PRE!.FIX" or "}TMP{.FIL" (yes, both these are legitimate filenames under MS-DOS).

These different methods should help make handling DOS environment variables easier. Please write me if you find any of these examples to be unclear or in need of improvement.

Kind regards,

Eric Pement (Acts 17:29-31, Titus 2:11-14)

[eof]