CS 46A Lab 7
Advanced DOS

Department of Mathematics and Computer Science
San Jose State University

Review of DOS

In Lab 1 it was noted that, while many disk and file management commands can be carried out from a graphical user interface such as Microsoft Windows, using DOS can be faster, particularly for repetitive tasks. In this lab you will learn how to automate DOS by creating batch files consisting of sequences of DOS commands that can be executed again and again (indeed, writing batch files is a kind of programming). First, however, this lab will help you to review what you learned in Lab 1 about DOS.

  1. List all DOS commands that you learned in Lab 1.
  2. For this lab, you need to open a DOS command prompt window in Windows. How did you do it?

  3. For this lab, you need two formatted empty floppy disks. Format the two disks now if they are not already formatted.

    For this lab, you need a directory j:\cs46a\lab\lab6, and inside this directory a directory work. Make these subdirectories now from the DOS prompt, and then copy all the files from k:\cs46alab\lab6 to j:\cs46a\lab\lab6.

  4. ? What commands did you use?

  5. Change the current directory to k:\cs46alab and issue a dir /s /p command.

  6. How many files do you find?
  7. What is the significance of the /p?

  8. Now issue the command

    dir /s pastri.cpp
     
     

  9. What is the absolute path to this file?

  10. Now issue the commands

    j:

    cd \cs46a\lab\lab6

    xcopy /s k:\cs46alab\*.* work
     
     

  11. Look at the contents of work. Draw the directory structure.
  12. How is the xcopy instruction above different from the following command?

  13. copy k:\cs46alab\*.* work
     
     

    Make a directory named to in your current directory, copy the file k:\cs46alab\lab6\hello.cpp to work, and then move it to to.

  14. What commands did you use?

  15. Now rename the directory to as target, and then delete the directory target.

  16. What commands did you use?

  17. Batch Files

    Every day you log onto the computer, you do many of the same things:

    1. Run doskey/insert (just to make sure it's installed, and with the right option).

    2. Copy any files that you have worked on at home from a: to j:.

    3. Change to the j:\cs46a\lab directory (or to another similar directory).

    Rather than typing the commands every time, you can place them into a batch file, and run the batch file as a single command under DOS. We will start with a simple version of such a batch file.

    Start Notepad from the Programs | Accessories menu. Type in the following text:

    @echo off

    rem Startup batch file

    doskey /insert

    cd work

    rem Copy all files for now

    copy a:*.*
     
     

    Then use the File | Save as menu option to save the file as j:\cs46a\lab\lab6\start.txt. (Notepad will automatically give it the txt extension, so you should just type start in the filename field of the dialog box. Now exit Notepad and change the name of the file (using Explorer or the DOS move command) to start.bat (all batch files must have the bat file extension).

    You can use also the editor of the MSDS C++ compiler to edit any text files, not just code files, but Notepad is easy to use too. One advantage to using MSDS is that you can save the file directly as a .bat file, without changing the name.

    Now switch back to the DOS Command Prompt, make sure the current directory is still j:\cs46a\lab\lab6, put a disk in drive a:, and type

    start [Enter]
     
     

  18. What happened?

  19. You execute the commands in a batch file by typing the name of the file (without the extension .bat).

    The first two commands of the start batch file are new commands. @echo off suppresses the display of each command on the screen as it is executed. A line starting with rem contains comments that are ignored by DOS.

  20. Comment out the line @echo off (by prefixing it with rem). Run the batch file. What is the difference?

  21. When you are done for the day, you should back up all your work. Of course, you could simply do

    copy *.* a:
     
     

    but then you copy all the .obj and .bak files that you don't really need. Copying takes time and causes wear and tear on the floppy. Most importantly, your disk may fill up with junk files, leaving you with insufficient space for the files you need. Really, you mostly want to copy all files with extension .cpp, .h, .txt and .bat.

  22. Make a batch file named save.bat to do that job. What lines does your batch file contain?

  23. Batch File Arguments

    Suppose you sometimes want to save your work to a:, other times possibly to b:, and maybe you even want to use the same batch file to copy to j: from a: or k: or even to c: at home. This can be easily done by modifying save.bat.

    Change the lines

    copy ... a:
     
     

    to

    copy ... %1:
     
     

    (Be sure to place the colon after the %1)

    Run save a

    Note that %1 has been replaced by a. %1 is the first argument of the batch file, %2 is the second, and so on.

  24. Type save without an argument. What happens?

  25. Let's modify the batch file to give an error message if no command line argument is specified.

    Add the following lines:

    if "%1" == "" goto error
     
     

    (keep the copy commands here)

    goto end

    :error

    echo Usage: save drive

    echo Example: save a
     
     

    :end
     
     

  26. Now type save without an argument. What happens?

  27. The if "a" == "b" command tests whether the strings a and b are equal. The goto command goes to a label. Each label starts with a colon (:). The echo command displays a message on the screen.

  28. What happens if you type save a: (instead of save a)?

  29. Let us add more error checking. We want to see that the argument is an existing drive. Add the following lines after the if "%1" == "" goto error
     
     

    for %%f in (A,a,B,b,C,c,J,j) do if "%1" == "%%f" goto ok

    goto error

    :ok

  30. Now type save a and save a:. What happens in each case?

  31. Redirection

    Suppose you want to print a directory listing. How can you do it? Dir shows the display of the directory on the screen. If it happens to fit on one screen, you can use the Edit option of the shortcut menu of the DOS window to copy any part of the screen to the Windows Clipboard, and then paste it into Notepad. There is a better way.

    Type the following commands
     
     

    k:

    cd \cs46alab\lab6

    dir /S > j:\cs46a\lab\lab6\out.txt

    j:

    cd \cs46a\lab\lab6
     
     

    Then view the file out.txt:

    notepad out.txt

    The redirection > out.txt sent all output to a file instead of the screen. Now you can look at the file, edit it, or print it with Notepad or the MSDS editor.

  32. Redirection works with all commands that write output to the screen. What command do you type to save the directory tree of the k: drive in the file named kdirs.txt

  33. The tree command outputs DOS graphics characters to the screen, which are not recognized in Windows applications. Thus, if you look the file kdirs.txt in Notepad, it will not be correct. In the MSDS editor, however, it will look correct.

    You can also supply the input to programs in a file rather than keying it in. Consider the following example.

    del work
     
     

  34. Try out this command. What question does del ask?

  35. You must enter a Y if you want del to go ahead. When the del command is contained in a batch file, it will be irritating if the user has to enter Y at just the right time. But we can store the input in a file.
     
     

    Prepare a file y.txt that contains just one line with just the letter Y followed by [Enter]. Then type

    del work < y.txt

    Now del reads the Y keystroke from the file y.txt. You can place this line in a batch file, and the batch file will run silently without bothering the user.

    Some commands are specifically designed to work with input from the keyboard (thus allowing redirected input). The sort program is an example.

    Try the following:

    sort < out.txt

  36. What is the result?
  37. How can you place the sorted directory listing in another file named sortout.txt?

  38. The sort program reads from standard input (that is, the keyboard or a redirected file). It is possible (although not very useful) to have sort sort some lines of keyboard input.

    Type sort and then the following lines. Hit [Enter] after each line. The [Ctrl-Z] command tells DOS to end keyboard input.

    This

    is

    a

    test

    [Ctrl+z]

  39. What is the output?

  40. Try sort without the <

    sort out.txt
     
     

  41. What happens? (If the computer appears to hang, type [Ctrl+Z] and [Enter].)

  42. To sort a directory, you can first type dir > out.txt and then sort < out.txt. Because this combination is so frequent, there is a shortcut for it, called a pipe.

    Type in the following:

    dir | sort

    This pipe, written with a vertical bar, runs dir, stores its output in a temporary file, then runs sort and redirects its input from that temporary file, and then automatically deletes the temporary file.

    Another useful program that reads from standard input is more. More stops every screen full and waits for you to hit a key before continuing.

    Type in

    dir /S | more

    You can pipe any sequence of commands together.

    Type in

    dir /S | sort | more
     
     

  43. What is the effect of echo Y | del a:*.*?
  44. echo Y | del a:*.* is more typing than just responding Y to the "Delete all files" question. However, it does come in handy if you need to clean more than one disk. Why? (Hint: doskey)
  45. What would you prefer to use in a batch file to clean out disk a: without bothering the user to type a "Y",

  46. echo Y | del a:*.*

    or

    del a:*.* < y.txt
     
     

    Why?

    Writing your own Filters

    A program that reads from standard input and writes to standard output is often called a filter. More and sort are examples of filters. In this exercise, we will write our own filter that adds line numbers to a file.

    Compile the program linenum.cpp (or use the supplied .exe file).

    Run

    linenum < hello.cpp

  47. What is the output?

  48. To create a file with tabs expanded to spaces and with line numbers, use (the tab program is from Lab 2):

    tab < hello.cpp | linenum > hello.txt

    Make a batch file pprint.bat that creates a "pretty print" version of its first argument in a file whose name is given by its second argument. The "pretty print" version should have tabs expanded to spaces and line numbers. For example,

    pprint hello.cpp hello.txt

    should have the same effect as the previous command.

  49. What command(s) do you place in the batch file?

  50. Error Level

    Look at the hello.cpp program:

    int main()

    {
       cout << "Hello, World!\n";

       return EXIT_SUCCESS;

    }

    The main() function returns EXIT_SUCCESS, although it is not clear how anyone could test its return value. You may have heard that the convention is to return 0 when a program is successful and a non-zero value to indicate some kind of error. The debugger actually shows the return value of the program. More importantly, you can test the return value of a program in a batch file.

    Consider the program fcomp.cpp with the following main() function. The program takes two file names on the command line, returns 0 if two files are identical, 1 if the files differ, and 2 if one or both files don't exist.

    int main(int argc, char* argv[])
    { fstream f1; /* first file to compare */
       fstream f2; /* second file to compare */
       string ch1; /* character from first file */
       string ch2; /* character from second file */

       if (argc != 3) return 2;
       f1.open(argv[1], ios::in);
       if (f1.fail()) return 2;
       f2.open(argv[2], ios::in);
       if (f2.fail()) return 2;
       do
       {   ch1 = get_char(f1);
          ch2 = get_char(f2);
          if (ch1 != ch2) return 1;
       } while (!f1.eof() && !f2.eof());
       return 0;
    }

    Type in the following commands:

    copy hello.cpp hello.bak

    fcomp hello.cpp hello.bak

  51. What result do you get from the last command?

  52. The following batch file, named filecomp.bat, can test the return value of main.

    @echo off
    fcomp %1 %2
    if errorlevel 2 goto error
    if errorlevel 1 goto different
    echo %1 and %2 are identical
    goto end

    :different
    echo %1 and %2 are different
    goto end

    :error
    echo %1 or %2 does not exist

    :end

    The test "if errorlevel 1" really means "if the error level is >= 1". For that reason, we first have to test for error level 2, then for error level 1.

    Run the following:

    filecomp hello.cpp hello.bak

    filecomp hello.cpp fcomp.cpp

    filecomp yellow.cpp fcomp.cpp

  53. What results do you get?

  54. We now go on to make a really useful batch file, for backing up your work every day. If you work in more than one place, you carry floppies with your files. You copy those files from floppies to hard disks on the computers that you use. You end up with different versions of the same file. If you are not careful, you can easily copy an older version onto a newer version of the same file, maybe wiping out several hours of work.

    What we need is a mechanism that copies newer files onto older files but never older files over newer files.

    DOS keeps track of the time that a file was last modified. You can see this time in the dir command.

  55. When was the file filecomp.bat last modified?

  56. The program timecomp.cpp (timecomp.exe is also supplied) compares the times of last modification of two files. It returns :

    3 if one of the files doesn't exist
    2 if the first file is newer than the second
    1 if the files have the same age
    0 if the first file is older than the second

    We only want to copy a file if it is newer than the target, or if the target doesn't exist. That is, we want to test for error level >= 2. The following batch file, backfile.bat, does that:

    @echo off
    timecomp %1 %2
    if errorlevel 2 goto copy
    echo Skipping %1
    goto end
    :copy
    echo Backing up %1
    copy %1 %2 > nul
    :end

    Try it out. Put a disk in drive a: and enter the following commands:

    backfile hello.cpp a:hello.cpp

    Now edit hello.cpp to print "Hello, cruel world" and enter the commands

    backfile a:hello.cpp hello.cpp

    backfile hello.cpp a:hello.cpp

  57. Which backfile operation copied the file, and which ones skipped it?

  58. backfile.bat shows some fancy batch file techniques. Note that we can use the argument %1 in the echo command. The "> nul" in the copy command sends the line "1 file(s) copied" to the special device nul rather than the display. Anything sent to nul just disappears.

    So far, backfile is a safer version of copy. It will only copy a new file onto an older one. To make it really convenient to do a backup, here is another file backall.bat that backs up all *.cpp *.h, *.txt, and *.bat files.

    @echo off
    for %%f in (A,a,B,b,C,c,J,j) do if "%%f" == "%1" goto ok
    echo Usage: backall drive
    echo Example: backall a
    goto end
    :ok
    for %%f in (*.cpp) do call backfile %%f %1:%%f
    for %%f in (*.h) do call backfile %%f %1:%%f
    for %%f in (*.txt) do call backfile %%f %1:%%f
    for %%f in (*.bat) do call backfile %%f %1:%%f
    :end

    Try it out:

    backall a

  59. Which files were copied, and which were skipped?

  60. Do it again:

    backall a

  61. Which files were copied, and which were skipped?

  62. Do the following:

    del a:hello.*

    backall a

  63. Which files were copied, and which were skipped?

  64. backall.bat shows more fancy batch file technique. There are two forms of the for loop. for var in (list) steps through all items in the list. for var in (pattern) steps through all files matching the pattern. In a batch file, var is always of the form %%letter. To call one batch file from another, you must use call.

    You should really use backall. When you start working, switch to the a: drive and do a backall j. When you are done, do a backall a from the j: drive. It is a quick way of keeping your files synchronized.

  65. You want to give backall to a friend. Which files do you need to copy?

  66. grep

    The grep program is an indispensable utility to quickly look inside a number of files. Unfortunately, it is not a standard part of DOS, so we supply it as an executable file grep.com in the lab6 files. We'll start with a simple example.

    Make sure your current directory is j:\cs46a\lab\lab6 and type

    grep errorlevel *.bat
     
     

  67. What output did you get?

  68. This is the simplest, and most common usage of grep. You get a list of all lines containing the string pattern (the first argument to grep), in all matching files (the second argument to grep).

    A very common use for grep is to answer the question "Which !@#$ header file must I include to use a standard C++ definition"?

    You want to find the directory containing the standard header files (e.g. stdlib.h, iostream.h, math.h, etc.). Try the following (do this for all defined drives on your system except a: and b:) :

    dir /s c:iostream.h

    dir /s j:iostream.h

    dir /s k:iostream.h

  69. Which drive/directory contains the C++ header files?

  70. Now let us find which header defines the random number generator rand:

    grep rand ??\*.h

    (Replace the double question mark with the drive and directory that you found in the previous step.)

  71. Which file(s) contained the string rand? Which header file do you need to #include to call rand?
  72. How would you find out which file to include to call rand( ) if you didn't have grep?

  73. The name "grep" stands for "global regular expression print". That means we can look for regular expressions, not just patterns. One of the most useful regular expressions is the one below, to scan a C++ file for "magic numbers".

    Try

    grep [^A-Za-z][0-9]+ timecomp.cpp
     
     

  74. What output do you get? Which of them point to "magic numbers"?

  75. The syntax for regular expressions is not easy to remember, and there is no glory in trying to. The grep program will give you help on its arguments and the regular expression syntax.

    Find the help screen. (Hint: Type grep with no arguments.)

  76. What command do you issue to print out the help screen? (Hint: Use redirection.)
  77. What grep options do you use to match whole words only (e.g. rand doesn't match random)? To use case-insensitive match (e.g. rand matches Rand)?

  78. Sometimes grep prints so many lines that the output is overwhelming.

    To find the definitions of max or min, try

    grep m[ai][xn] ??\*.h

    (Again, replace the double question mark with the directory containing the C++ header files that you found previously in this lab.)

    Whoa! That was too much. Of course, you can use

    grep m[ai][xn] ??\*.h | more

    to look at the output a screen at a time. But in this situation, one would like to first narrow down the selection of files. The grep output lists the files in the format "File ...\string.h". We'd like to just extract the lines starting with the word "File" from the grep output. And we know a tool to do that extraction, namely grep!

    Try

    grep m[ai][xn] n:\include\*.h | grep ^File | more

  79. What output did you get?
Checked by lab supervisor

Date __________________

Initials_________________