Windows batch files (.bat) coding style standard
https://softwareengineering.stackexchange.com/questions/329178
-
25-12-2020 - |
Question
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...
Solution
- 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".
OTHER TIPS
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.