Avoiding Spaghetti Code in Batch Files


  1. Posts : 10
    Windows 7 64-Bit
       #1

    Avoiding Spaghetti Code in Batch Files


    I've been reading how to avoid spaghetti code in batch files(Batch files - GOTO, and How To Avoid "Spaghetti Code").

    In the example of what spaghetti code is, I realized that the batch file that I use when I logon almost fits this example. Could someone please help me make my batch file more robust, and not have spaghetti code?

    Code:
    @ECHO OFF
    CLS
    
    
    :MENU
    echo Welcome %USERNAME%
    
    echo 1 - Start KeePass
    echo 2 - Backup
    echo 3 - FireFox
    echo 4 - Exit
    
    SET /P M=Please Enter Selection, then Press Enter:
    
    IF %M%==1 GOTO StarKeePass
    IF %M%==2 GOTO Backup
    IF %M%==3 GOTO FireFox
    IF %M%==4 GOTO :EOF
    GOTO MENU
    
    
    :StarKeePass
    SET keePass="%USERPROFILE%\KeePass\KeePass-2.30\KeePass.exe"
    SET kdb="%USERPROFILE%\KeePass\PasswordDatabase\PasswordDatabase.kdbx"
    
    echo I'll start KeePass for You
    START "" %keePass% %kdb% 
    
    GOTO MENU
    
    :Backup
    SET backup="%USERPROFILE%\backup.bat"
    call %backup%
    
    GOTO MENU
    
    :FireFox
    cd "C:\Program Files (x86)\Mozilla Firefox\"
    start firefox.exe
    
    GOTO MENU
      My Computer


  2. Posts : 6,285
    Windows 10 Pro X64
       #2

    That is not spaghetti code. It's very readable and easy to understand. No need to complicate it.
      My Computer


  3. Posts : 721
    Windows 10, Windows 8.1 Pro, Windows 7 Professional, OS X El Capitan
       #3

    Hi JBourne,

    I'm impressed with your athirst for better looking code. But you should realise that batch was never designed to be pretty; it's probably the most ugliest language there is. Be as messy as you want. Certainly, no one is ever going to tell you off for spaghetti code in batch.

    That being said, I do very much dislike Goto myself. Using Goto is generally considered bad practise because it is notorious for making code an unsightly mess: "spaghetti code". I'd never use a Goto statement in a batch if I could. Unfortunately, there are a couple of instances in batch where you are pretty much forced use Goto. For instance, if you need to instate a while loop (which batch doesn't provide a statement for), there's not much choice but to construct one out of labels and Gotos.

    In most cases a label and its associated Goto can be replaced by a function. Functions neaten programs by giving them more 'structure'. Though batch files don't have real functions, a nice standard has been developed. Here's an example of using functions in batch, complete with parameters and return values:

    FunctionsInBatch.bat
    Code:
    @echo off
    goto :main
    
    :add_two_numbers Num1 Num2
    setlocal
    	set /a result=%1 + %2
    endlocal & set /a result=%RESULT%
    goto :eof
    
    :multiply_two_numbers Num1 Num2
    setlocal
    	set /a result=%1 * %2
    endlocal & set /a result=%RESULT%
    goto :eof
    
    :evaluate_two_numbers Num1 Num2 Operator
    setlocal
    	set /a result=%1 %3 %2
    endlocal & set /a result=%RESULT%
    goto :eof
    
    :main
    set/p=12 plus 6 is <NUL
    call :add_two_numbers 12 6
    echo %RESULT%!
    
    set/p=4 times 26 is <NUL
    call :multiply_two_numbers 4 24
    echo %RESULT%!
    
    set/p=the remainer of 99 divided by 4 is <NUL
    call :evaluate_two_numbers 99 4 %%%%
    echo %RESULT%!
    If you wish to implement functions effectively in batch, I suggest studying RootOfTheNull's (channel now renamed to 'John Hammond') Basic Functions tutorial up to his tutorial #26. I highly recommend watching a hand full of that YouTuber's batch series if you wish to delve deeper into the anomalous language of batch.


    JBourne, for your interest, I've rewritten your batch file the exact way I would write it.
    Code:
    @echo off
    goto :main
    
    :StarKeePass
    	set keePass="%USERPROFILE%\KeePass\KeePass-2.30\KeePass.exe"
    	set kdb="%USERPROFILE%\KeePass\PasswordDatabase\PasswordDatabase.kdbx"
    	echo I'll start KeePass for You
    	START "" %keePass% %kdb%
    goto :eof
    
    :Backup
    	set backup="%USERPROFILE%\backup.bat"
    	call %backup%
    goto :eof
    
    :FireFox
    	start "" "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
    goto :eof
    
    :main
    cls
    echo.& echo Welcome %USERNAME%,& echo.
    echo   1 - Start KeePass
    echo   2 - Backup
    echo   3 - FireFox
    echo   4 - Exit
    echo. 
    
    choice /c "1234" /t 20 /d "4" /m "Please Type Selection, then Press Enter:"
    echo.
    if not errorlevel 2 call :StarKeePass
    if not errorlevel 3 call :Backup
    if not errorlevel 4 call :FireFox
    if not errorlevel 5 goto :eof
    goto :main
    Note the "goto :main" near the top of the script can be found in all my batch files that use functions, which, aside from creating while loops (such as the functionality of the "goto :main" at the bottom), is the only time I would reckon to use a Goto.


    If I must state a conclusion here, forget that Robvanderwoude article and just go with a style that you enjoy writing in, which is easy for you to read. A script will be better managed if you write it yourself.
      My Computer


  4. Posts : 6,285
    Windows 10 Pro X64
       #4

    You have 4 Gotos in your batch file, JBourne also had 4 :) :)

    Just sayin ...
      My Computer


  5. Posts : 318
    Windows 10 x64
       #5

    Pyro has it right. Cmd batch language is lame. It traces its roots back to the early '70s with the CP/M operating system. It was garbage in the 20th century, and ought to be abolished in the 21st.

    If you want better code, use a better language.
    bash is better.
    powershell is better.
      My Computer


  6. Posts : 6,285
    Windows 10 Pro X64
       #6

    Batch is the easiest for novices though. It can do some pretty amazing things. Some of the batch scripts Pyprohly has posted in response to people looking for help have been excellent.
      My Computer


  7. Posts : 721
    Windows 10, Windows 8.1 Pro, Windows 7 Professional, OS X El Capitan
       #7

    Ztruker said:
    You have 4 Gotos in your batch file, JBourne also had 4 :) :)

    Just sayin ...
    Well, as you know, "goto :eof" takes on a special meaning. Most of the "goto :eof" statements in my batch program, specifically the ones that conclude each function, may of course be replaced with "exit /b" which is functionally equivalent to "goto :eof". "Goto :eof" is just more commonly used by batch-ers than "exit /b" for some reason.

    Furthermore, rearranging the structure of the program slightly, moving the ":main" section further to the top of the script will eliminate another Goto. But this would mean having functions below the main algorithm. It is good programming practise to declare functions and variables at the top of a program.

    Here's the batch file I describe, which has as few Gotos as possible.
    Code:
    @echo off
    :main
    cls
    echo.& echo Welcome %USERNAME%,& echo.
    echo   1 - Start KeePass
    echo   2 - Backup
    echo   3 - FireFox
    echo   4 - Exit
    echo. 
     
    choice /c "1234" /t 20 /d "4" /m "Please Type Selection, then Press Enter:"
    echo.
    if not errorlevel 2 call :StarKeePass
    if not errorlevel 3 call :Backup
    if not errorlevel 4 call :FireFox
    if not errorlevel 5 exit /b
    goto :main
     
    :StarKeePass
    	set keePass="%USERPROFILE%\KeePass\KeePass-2.30\KeePass.exe"
    	set kdb="%USERPROFILE%\KeePass\PasswordDatabase\PasswordDatabase.kdbx"
    	echo I'll start KeePass for You
    	start "" %keePass% %kdb%
    exit /b
     
    :Backup
    	set backup="%USERPROFILE%\backup.bat"
    	call %backup%
    exit /b
     
    :FireFox
    	start "" "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
    exit /b
    ... The result is a grand total of one Goto statement. This last Goto cannot be avoided as it is part of a while loop construct—using Gotos and labels is the only stable way to replicate a while loop in the batch language.


    margrave said:
    Cmd batch language is lame. [...] It was garbage in the 20th century, and ought to be abolished in the 21st.
    Unfortunately or fortunately, we won't be seeing batch files completely disappear from our Windows any time soon—only fade.

    Here's what PowerShell expert Jeffrey Snover (one of the designers and developers of PowerShell) had to say about batch files when they were mentioned in an interview about PowerShell,
    Erik Meijer: And so no more batch files now--?
    Jeffrey Snover: Well, they'll still be there. They're like some... disease you die with but not of. Uh, and...
    Erik Meijer & Jeffrey Snover: *chuckles*
    Jeffrey Snover: Well, you know, you can't get rid of that stuff. But yeah, I think you'll see fewer and fewer usages of them.

    Ztruker said:
    Batch is the easiest for novices though.
    Though that is up for debate. I'm sure many would agree that PowerShell is more intuitive and user-friendly than batch.
      My Computer


  8. Posts : 4,049
    W7 Ultimate SP1, LM19.2 MATE, W10 Home 1703, W10 Pro 1703 VM, #All 64 bit
       #8

    You could also use a Visual Basic script.
      My Computer


  9. Posts : 6,285
    Windows 10 Pro X64
       #9

    If I need more than a batch file, I use Open Object Rexx. I started using Rexx on IBM mainframes in the 70s and have used it in one form or another on every PC I've owned since.

    Sample of the beginning of one of the Rexx programs I use every day to synchronize Seamonkey mail between my Desktop and laptop.

    Code:
    /****************************************************************************/
    /* Copy Mozilla Mail data between Laptop and Desktop. Direction based       */
    /* on where program is run.                                                 */
    /****************************************************************************/
    '@Echo off'
    ver='v1.0'
    Parse source whoami
    Parse value whoami with . . whoami
    Say Filespec('NAME',whoami) ver
    
    curdir=Directory()                                 /* remember where we are*/
    
    /***********************************/
    /* Register all REXXUTIL functions */
    /***********************************/
    rc=RxFuncAdd('SysLoadFuncs', 'REXXUTIL', 'SysLoadFuncs')
    If rc>1 then
      Do
        Say 'Unable to register REXXUTIL functions.'
        Signal Done
      End
    Call SysLoadFuncs
    
    /*********************/
    /* See if push wanted */
    /*********************/
    
    Arg p1 p2 p3 .
    If p1='/?' Then
      Signal Tell
    If p1 \= '' & Wordpos(p1,'DOIT PUSH FORCE TEST RICH MAUREEN') == 0 Then
      Do
        Say 'Invalid parameter: 'p1
        Signal Done
      End
    If p2 \= '' & Wordpos(p2,'DOIT PUSH FORCE TEST RICH MAUREEN') == 0 Then
      Do
        Say 'Invalid parameter: 'p2
        Signal Done
      End
    If p3 \= '' & Wordpos(p3,'DOIT PUSH FORCE TEST RICH MAUREEN') == 0 Then
      Do
        Say 'Invalid parameter: 'p3
        Signal Done
      End
      My Computer


  10. Posts : 51
    Win 7 Pro 64
       #10

    The more sophisticated programmers avoid "goto" statements[1] by using the "comefrom"[2]:

    1: E. W. Dijkstra, "GOTO Statement Considered Harmful," Letter of the Editor, Communications of the ACM, March 1968
    2: Clarke, Lawrence, "We don't know where to GOTO if we don't know where we've COME FROM. This linguistic innovation lives up to all expectations.", Datamation, 1973
      My Computer


 

  Related Discussions
Our Sites
Site Links
About Us
Windows 7 Forums is an independent web site and has not been authorized, sponsored, or otherwise approved by Microsoft Corporation. "Windows 7" and related materials are trademarks of Microsoft Corp.

© Designer Media Ltd
All times are GMT -5. The time now is 05:41.
Find Us