Section 7.4. Untangle GOTO-Based Batch Files


7.4. Untangle GOTO-Based Batch Files

Of all of the features of cmd.exe, two constructs have enabled batch file writers to create some very versatile scripts: the IF and GOTO statements. Although IF exists in MSH (albeit in a slightly different form), GOTO is notably absent. Thankfully, MSH functions, script flow control statements (if and switch), and script blocks are able to completely remove the need for the GOTO statement.

7.4.1. How Do I Do That?

The SHIFT command present in cmd.exe is used to shift all command-line arguments "up one." In other words, the first argument, %1, is dropped, %2 becomes %1, %3 becomes %2, and so on. Batch files can use this technique for processing each command-line argument in turn, as shown in Example 7-5.

Example 7-5. ProcessArguments.cmd
 @ECHO OFF :start ECHO Processing %1 SHIFT IF NOT "%1"=="" GOTO start

When given a set of options on the command line, this cmd.exe script will work through each in turn until none remains:

     C:\> ProcessArguments.cmd a b c     Processing a     Processing b     Processing c

MSH offers a different solution, and it is something we've already discussed. Remember that to an MSH script, all command-line arguments are available in the $args special variable array. An MSH script (like that shown in Example 7-6) can simply use a foreach statement to walk through the list to achieve the same result.

Example 7-6. ProcessArguments.msh
 foreach ($arg in $args) {     echo "Processing $arg" }

Now, let's take a look at a batch file that copies one file to a destination but makes sure not to overwrite the target. The batch file in Example 7-7 requires two options to be present on the command line when the script is called; if either is empty, it displays a short usage guide and exits.

Example 7-7. CautiousCopy.cmd
 @echo off IF "%1"=="" GOTO usage IF "%2"=="" GOTO usage IF EXIST %2 GOTO nooverwrite ECHO Executing copy %1 %2 GOTO end :nooverwrite ECHO Abort: Script will not overwrite %2 GOTO end :usage ECHO Usage information ECHO. ECHO   CautiousCopy.cmd file1 file2 GOTO end :end

To recreate the same functionality in an MSH script, it's important to focus on the goals of the batch file rather than its current implementation. The new script in Example 7-8 will check that the options are present, check whether the target exists, and perform the copy, in that order.

Example 7-8. CautiousCopy.msh
 if ($args.count -ne 2) {     echo "Usage"     echo ""     echo "  test.msh file1 file2"     exit } if (test-path $args[1]) {     echo "Abort: Script will not overwrite $($args[1])"     exit } echo "Executing copy $($args[0]) $($args[1])"

Although there is little difference in the lengths of the two scripts, the MSH version is somewhat more sequential and easier to follow, meaning that future changes should be that much easier.

Another use of the GOTO statement allows a batch file to call itself in a recursive fashion as Example 7-9 does. In the first run, the batch file sets up the loop and then calls itself to process each entry. Some marker is used (the RECURSIVEMODE option in this case) to indicate to the script that it is calling itself and should behave differently.

Example 7-9. ProcessFiles.cmd
 @echo off IF "%1"=="RECURSIVEMODE" GOTO recursiveBlock FOR %%f IN (*.*) DO @%0 RECURSIVEMODE %%f GOTO end :recursiveBlock ECHO Processing %2 :end

In MSH, it is relatively rare for a script to call itself in this fashion. Indeed, although Example 7-9 does call itself recursively, it is only doing so to solve an iterative task. Problems like these are well-suited to a looping construct such as the foreach statement, which we've already discussed; Example 7-10 is a cleaner MSH script that has the same effect.

Example 7-10. ProcessFiles.msh
 foreach ($file in $(get-childitem)) {     echo "Processing $file" }

7.4.2. What Just Happened?

By now, it should be apparent that, if nothing else, MSH can be used to write scripts that serve the same purpose as cmd.exe batch files. What's more, with some practice, the time taken to write and troubleshoot MSH scripts should decrease significantly.

Although the GOTO statement is an intuitive concept in a simple scripting language, its use can quickly lead to scripts that jump all over the place to do their work. They can become rigid such that even simple modifications or adjustments are nontrivial and troubleshooting problems can become expensive. In Examples 7-8, 7-9, and 7-10, the GOTO commands were a means to an end, providing some ability to either loop or control what happened next. In Chapter 3, we saw how these ideas are built into MSH, and it turns out that when the proper tools are available, there is often a more logical way to structure the script.

Of course, there are cases that fall outside of the examples covered here, and it might not be immediately obvious how to rework a batch file appropriately. Generally speaking, if several different places in the script call a GOTO to the same target, that target content should probably be wrapped up in an MSH function.

The removal of GOTO semantics is one of the more significant changes when facing a batch file to MSH migration, but now let's take a look at some of the similarities between the two shells.




Monad Jumpstart
Monad Jumpstart
ISBN: N/A
EAN: N/A
Year: 2005
Pages: 117

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net