5

Is there any standard/encouraged Windows batch file coding style?

I would think that if I want my batch files to be easy to read/mantain, I should care about this, but searching the web I found very little about it, and I didn't get any reviews (not even comments) on this Code Review question, so it makes me wonder if this is something I shouldn't care much about...

6
  • Are you talking abuout Linux/Unix scripts? Aug 24 '16 at 11:37
  • @TulainsCórdova Windows batch files. I just edited the question to make it clear. Aug 24 '16 at 11:48
  • @carlossierra I opened a bounty on it over on code review.
    – RubberDuck
    Aug 25 '16 at 2:05
  • 1
    @RubberDuck thanks for starting the bounty. I appreciate it!! Aug 25 '16 at 2:09
  • 1
    I just stumbled upon this Batch Style Guide – quite nice, though this claim is wrong, because there are implied endlocal calls when exiting a script (or sub-routine) – see setlocal /?
    – aschipfl
    Mar 26 '20 at 0:05
5
  • Naming, the file the variables, the functions.
  • Comments, what the script do, what that complicated portion of code do.
  • Isolate portion of code in functions
  • Consistency in the coding style, whatever you choose.

These are what makes code really maintenable whatever kind of code it is. Now batches are supposed to be quite short code and not so much files, so that's probably why there isn't that much about coding standard and so on.

If you have really a lot of batches, a documentation outside showing how they work together would proabably be needed.

To be honest i'm not used to batch, so i don't get everything about the syntax you use in your code review's post. But your works seems pretty fine to me, maybe people just didn't comment "i don't see anything wrong here".

1
  • Thanks for your suggestions and the positive comments about what you saw on my Code Review post. Encouraged by that, I took your ideas and mixed them with some ideas of mine to come up with a proposal that I just posted on the Code Review question. Aug 25 '16 at 2:25
6

When I am writing batch files, they usually rely on the following template:

@cls
@title Optional Title
@echo off
setlocal EnableExtensions DisableDelayedExpansion

::Comment that describes purpose and usage of the script; this should also
::contain (original) script name, version, date and author, as applicable.

rem Define global constants (read-only variables) here (names begin with `_`).

rem Initialise global variables (those accessed also by sub-routines) here,
rem if any (names begin with `$`).

rem Parse command line arguments and/or user input data here;
rem regard cases when too few or too many arguments are provided;
rem regard cases when user input is empty.

rem Place code for processing here:
rem In general, avoid non-ASCII characters within functional code;
rem use lower-case (for commands, sub-commands, verbs and keywords);
rem use upper-case only for switches, variable names and `for` references;
rem place single space between commands, switches and arguments;
rem place single spaces around redirection operators too;
rem avoid excessive line concatenation (by `&`); avoid line continuation (by `^`);
rem put quotation marks around file and directory paths/names;
rem insert explanatory comments using the `rem` command.
(
    rem Indent parenthesised blocks.
)

rem Return resulting output here.

endlocal
exit /B


:SUB  rtn_return  ref_variable  val_value
    ::Comment that describes purpose and usage of the sub-routine;
    ::include the meanings of the aforementioned arguments (like:
    ::`rtn_*` denote return values, so they hold variable names;
    ::`ref_*` denote references, so they hold variable names too;
    ::`val_*` denote values, so they hold immediate values).
    setlocal DisableDelayedExpansion
    
    rem Define local constants here (names begin with `_`).
    
    rem Parse arguments here; check whether too few/many arguments are given;
    
    rem Place code for processing here.
    
    rem Return resulting output here; regard the `endlocal` barrier
    rem (for `rtn_*` arguments, whose values need to survive it).
    
    endlocal
    exit /B

If a help system (support for /? switch) is about to be implemented, I usually use this template:

@cls
@title Optional Title
@echo off
setlocal EnableExtensions DisableDelayedExpansion

::Comment that describes purpose and usage of the script; this should also
::contain (original) script name, version, date and author, as applicable.

::::
::::"%~nx0"  [version 0.0]
::::
::::Help message text that describes the purpose of the script in detail;
::::some parts of that text may be placed elsewhere in the script.
::::The continued text could describe the exact usage of the script,
::::illustrating the syntax and listing all the accepted parameters.
::::

rem Define global constants (read-only variables) here (names begin with `_`).

rem Initialise global variables (those accessed also by sub-routines) here,
rem if any (names begin with `$`).

rem Parse command line arguments and/or user input data here;
rem regard cases when too few or too many arguments are provided;
rem regard cases when user input is empty.
if "%~1"=="/?" call :HELPER & exit /B

rem Place code for processing here:
rem In general, avoid non-ASCII characters within functional code;
rem use lower-case (for commands, sub-commands, verbs and keywords);
rem use upper-case only for switches, variable names and `for` references;
rem place single space between commands, switches and arguments;
rem place single spaces around redirection operators too;
rem avoid excessive line concatenation (by `&`); avoid line continuation (by `^`);
rem put quotation marks around file and directory paths/names;
rem insert explanatory comments using the `rem` command.
(
    rem Indent parenthesised blocks.
)

rem Return resulting output here.

endlocal
exit /B


:SUB  rtn_return  ref_variable  val_value
    ::Comment that describes purpose and usage of the sub-routine;
    ::include the meanings of the aforementioned arguments (like:
    ::`rtn_*` denote return values, so they hold variable names;
    ::`ref_*` denote references, so they hold variable names too;
    ::`val_*` denote values, so they hold immediate values).
    setlocal DisableDelayedExpansion
    
    rem Define local constants here (names begin with `_`).
    
    rem Parse arguments here; check whether too few/many arguments are given;
    
    rem Place code for processing here.
    
    rem Return resulting output here; regard the `endlocal` barrier
    rem (for `rtn_*` arguments, whose values need to survive it).
    
    endlocal
    exit /B


:HELPER
    ::This sub-routine returns the help text embedded in this script preceded by `::::`;
    ::note that `%`-expansion is only done when `%` occurs within a line of text, which
    ::allows usage of argument references and variables; regard that each literal `%`
    ::must be doubled to `%%`:
    setlocal DisableDelayedExpansion
    for /F "delims=" %%H in ('^""%__AppDir__%findstr.exe" /B /L "::::" "%~f0"^"') do (
        set "LINE=%%H"
        setlocal EnableDelayedExpansion
        if not "!LINE:%%=!"=="!LINE!" (
            set "LINE=!LINE:"=""!^"
            for /F "delims=" %%G in ("!LINE!") do (
                endlocal
                call set "LINE=%%G"
                setlocal EnableDelayedExpansion
                set "LINE=!LINE:^^=^!"
            )
            set "LINE=!LINE:""="!^"
        )
        echo(!LINE:*::::=!
        endlocal
    )
    endlocal
    exit /B


::::
::::  USAGE:
::::
::::    %~nx0 [/optional] [/switch] {/alternative | /switches} parameter ...
::::    %~nx0 /?
::::
::::  PARAMETERS:
::::
::::    parameter     required parameter (... means that more such are accepted)
::::    /optional     optional switch
::::    /switch       optional switch
::::    /alternative  alternative switch
::::    /switches     alternative switch
::::    /?            displays this help text;
::::
::::  ERRORLEVEL:
::::
::::    0   successful completion;
::::

Check out all the comments which hold the most important coding style recommendations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.