Windows batch script to read an .ini file Windows batch script to read an .ini file windows windows

Windows batch script to read an .ini file


Here's a command file (ini.cmd) you can use to extract the relevant values:

@setlocal enableextensions enabledelayedexpansion@echo offset file=%~1set area=[%~2]set key=%~3set currarea=for /f "usebackq delims=" %%a in ("!file!") do (    set ln=%%a    if "x!ln:~0,1!"=="x[" (        set currarea=!ln!    ) else (        for /f "tokens=1,2 delims==" %%b in ("!ln!") do (            set currkey=%%b            set currval=%%c            if "x!area!"=="x!currarea!" if "x!key!"=="x!currkey!" (                echo !currval!            )        )    ))endlocal

And here's a transcript showing it in action (I've manually indented the output to make it easier to read):

c:\src>type ini.ini    [SectionName]    total=4    [AnotherSectionName]    total=7    [OtherSectionName]    total=12c:\src>ini.cmd ini.ini SectionName total    4c:\src>ini.cmd ini.ini AnotherSectionName total    7c:\src>ini.cmd ini.ini OtherSectionName total    12

To actually use this in another cmd file, just replace the echo %val% line below with whatever you want to do with it):

for /f "delims=" %%a in ('call ini.cmd ini.ini AnotherSectionName total') do (    set val=%%a)echo %val%


I know I'm a little late to the party, but I decided to write a general purpose ini file utility batch script to address this question.

The script will let you retrieve or modify values in an ini-style file. Its searches are case-insensitive, and it preserves blank lines in the ini file. In essence, it allows you to interact with an ini file as a sort of very rudimentary database.

This script will work fine if you're reading / writing only alphanumeric values or symbols that have no special meaning to the cmd interpreter. If you need something capable of handling values containing ampersands, percents, etc, see the Update section below.

:: --------------------:: ini.bat:: ini.bat /? for usage:: --------------------@echo offsetlocal enabledelayedexpansiongoto begin:usageecho Usage: %~nx0 /i item [/v value] [/s section] inifileecho;echo Take the following ini file for example:echo;echo    [Config]echo    password=1234echo    usertries=0echo    allowterminate=0echo;echo To read the "password" value:echo    %~nx0 /s Config /i password inifileecho;echo To change the "usertries" value to 5:echo    %~nx0 /s Config /i usertries /v 5 inifileecho;echo In the above examples, "/s Config" is optional, but will allow the selection ofecho a specific item where the ini file contains similar items in multiple sections.goto :EOF:beginif "%~1"=="" goto usagefor %%I in (item value section found) do set %%I=for %%I in (%*) do (    if defined next (        if !next!==/i set item=%%I        if !next!==/v set value=%%I        if !next!==/s set section=%%I        set next=    ) else (        for %%x in (/i /v /s) do if "%%~I"=="%%x" set "next=%%~I"        if not defined next (            set "arg=%%~I"            if "!arg:~0,1!"=="/" (                1>&2 echo Error: Unrecognized option "%%~I"                1>&2 echo;                1>&2 call :usage                exit /b 1            ) else set "inifile=%%~I"        )    ))for %%I in (item inifile) do if not defined %%I goto usageif not exist "%inifile%" (    1>&2 echo Error: %inifile% not found.    exit /b 1)if not defined section (    if not defined value (        for /f "usebackq tokens=2 delims==" %%I in (`findstr /i "^%item%\=" "%inifile%"`) do (            echo(%%I        )    ) else (        for /f "usebackq delims=" %%I in (`findstr /n "^" "%inifile%"`) do (            set "line=%%I" && set "line=!line:*:=!"            echo(!line! | findstr /i "^%item%\=" >NUL && (                1>>"%inifile%.1" echo(%item%=%value%                echo(%value%            ) || 1>>"%inifile%.1" echo(!line!        )    )) else (    for /f "usebackq delims=" %%I in (`findstr /n "^" "%inifile%"`) do (        set "line=%%I" && set "line=!line:*:=!"        if defined found (            if defined value (                echo(!line! | findstr /i "^%item%\=" >NUL && (                    1>>"%inifile%.1" echo(%item%=%value%                    echo(%value%                    set found=                ) || 1>>"%inifile%.1" echo(!line!            ) else echo(!line! | findstr /i "^%item%\=" >NUL && (                for /f "tokens=2 delims==" %%x in ("!line!") do (                    echo(%%x                    exit /b 0                )            )        ) else (            if defined value (1>>"%inifile%.1" echo(!line!)            echo(!line! | find /i "[%section%]" >NUL && set found=1        )    ))if exist "%inifile%.1" move /y "%inifile%.1" "%inifile%">NUL

Example

Contents of example.ini:

[SectionName]; This is a comment.total=4[AnotherSectionName]# This is another comment.total=7[OtherSectionName]And it should work with non-standard comments as well.total=12

Test session:

C:\Users\me\Desktop>ini /s AnotherSectionName /i total example.ini7C:\Users\me\Desktop>ini /s othersectionname /i Total /v f00 example.inif00C:\Users\me\Desktop>type example.ini[SectionName]; This is a comment.total=4[AnotherSectionName]# This is another comment.total=7[OtherSectionName]And it should work with non-standard comments as well.Total=f00

Update

Apparently the pure batch solution chokes when it encounters characters like & (and probably % and others). So here's a more robust batch + JScript hybrid script that addresses that problem. The syntax and output are the same (but with an added /d switch to delete item=value pairs).

This script sets %ERRORLEVEL%=0 for success, and %ERRORLEVEL%=1 on error.

@if (@a==@b) @end /* -- batch / JScript hybrid line to begin JScript comment:: --------------------:: ini.bat:: ini.bat /? for usage:: --------------------@echo offsetlocal enabledelayedexpansiongoto begin:: color code by jeb -- https://stackoverflow.com/a/5344911/1683264:cset "param=^%~2" !set "param=!param:"=\"!"findstr /p /A:%1 "." "!param!\..\X" nul<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"exit /b:: but it doesn't handle slashes.  :(:s<NUL set /p "=/"&exit /b:usagefor /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do set "DEL=%%a"<nul > X set /p ".=."echo Usage:call :c 07 "   query:"call :c 0F " %~nx0 "&call :s&call :c 0F "i item ["&call :s&call :c 0F "s section] inifile"&echo;call :c 07 "   create or modify:"call :c 0F " %~nx0 "&call :s&call :c 0F "i item "&call :s&call :c 0F "v value ["&call :s&call :c 0F "s section] inifile"&echo;call :c 07 "   delete:"call :c 0F " %~nx0 "&call :s&call :c 0F "d item ["&call :s&call :c 0F "s section] inifile"&echo;echo;echo Take the following ini file for example:echo;echo    [Config]echo    password=1234echo    usertries=0echo    allowterminate=0echo;echo To read the "password" value:call :c 0F "   %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i password inifile"&echo;echo;echo To modify the "usertries" value to 5:call :c 0F "   %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i usertries "&call :s&call :c 0F "v 5 inifile"&echo;echo;echo To add a "timestamp" key with a value of the current date and time:call :c 0F "   %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i timestamp "&call :s&call :c 0F "v ""%DEL%%%%%date%%%% %%%%time%%%%""%DEL% inifile"&echo;echo;echo To delete the "allowterminate" key:call :c 0F "   %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "d allowterminate inifile"&echo;echo;call :c 07 "In the above examples, "&call :scall :c 0F "s Config "echo is optional, but will allow the selection ofecho a specific item where the ini file contains similar items in multiple sections.del Xgoto :EOF:beginif "%~1"=="" goto usagefor %%I in (item value section found) do set %%I=for %%I in (%*) do (    if defined next (        if !next!==/i set "item=%%~I"        if !next!==/v (            set modify=true            set "value=%%~I"        )        if !next!==/d (            set "item=%%~I"            set modify=true            set delete=true        )        if !next!==/s set "section=%%~I"        set next=    ) else (        for %%x in (/i /v /s /d) do if "%%~I"=="%%x" set "next=%%~I"        if not defined next (            set "arg=%%~I"            if "!arg:~0,1!"=="/" (                1>&2 echo Error: Unrecognized option "%%~I"                1>&2 echo;                1>&2 call :usage                exit /b 1            ) else set "inifile=%%~I"        )    ))for %%I in (item inifile) do if not defined %%I goto usageif not exist "%inifile%" (    1>&2 echo Error: %inifile% not found.    exit /b 1)cscript /nologo /e:jscript "%~f0" "%inifile%" "!section!" "!item!" "!value!" "%modify%" "%delete%"exit /b %ERRORLEVEL%:: Begin JScript portion */var inifile = WSH.Arguments(0),section = WSH.Arguments(1),item = WSH.Arguments(2),value = WSH.Arguments(3),modify = WSH.Arguments(4),del = WSH.Arguments(5),fso = new ActiveXObject("Scripting.FileSystemObject"),stream = fso.OpenTextFile(inifile, 1),// (stream.ReadAll() will not preserve blank lines.)data = [];while (!stream.atEndOfStream) { data.push(stream.ReadLine()); }stream.Close();// trims whitespace from edgesString.prototype.trim = function() { return this.replace(/^\s+|\s+$/,'') }// trim + toLowerCaseString.prototype.unify = function() { return this.trim().toLowerCase(); };// unquotes each side of "var"="value"String.prototype.splitEx = function(x) {    for (var i=0, ret = this.split(x) || []; i<ret.length; i++) {        ret[i] = ret[i].replace(/^['"](.*)['"]$/, function(m,$1){return $1});    };    return ret;}// splices a new element into an array just after the last non-empty element.  If first arg is a number, start at that position and look backwards.Array.prototype.cram = function() {    for (var args=[], i=0; i<arguments.length; i++) { args.push(arguments[i]); }    var i = (typeof args[0] == "number" && Math.floor(args[0]) == args[0]) ? args.shift() : this.length;    while (i>0 && !this[--i].length) {};    for (var j=0; j<args.length; j++) this.splice(++i, 0, args[j]);}function saveAndQuit() {    while (data && !data[data.length - 1].length) data.pop();    var stream = fso.OpenTextFile(inifile, 2, true);    stream.Write(data.join('\r\n') + '\r\n');    stream.Close();    WSH.Quit(0);}function fatal(err) {    WSH.StdErr.WriteLine(err);    WSH.Quit(1);}if (section && !/^\[.+\]$/.test(section)) section = '[' + section + ']';if (modify) {    if (section) {        for (var i=0; i<data.length; i++) {            if (data[i].unify() == section.unify()) {                for (var j=i + 1; j<data.length; j++) {                    if (/^\s*\[.+\]\s*$/.test(data[j])) break;                    var keyval = data[j].splitEx('=');                    if (keyval.length < 2) continue;                    var key = keyval.shift(), val = keyval.join('=');                    if (key.unify() == item.unify()) {                        if (del) data.splice(j, 1);                        else {                            data[j] = item + '=' + value;                            WSH.Echo(value.trim());                        }                        saveAndQuit();                    }                }                if (del) fatal(item + ' not found in ' + section + ' in ' + inifile);                data.cram(j ,item + '=' + value);                WSH.Echo(value.trim());                saveAndQuit();            }        }        if (del) fatal(section + ' not found in ' + inifile);        data.cram('\r\n' + section, item + '=' + value);        WSH.Echo(value.trim());        saveAndQuit();    }    else { // if (!section)        for (var i=0; i<data.length; i++) {            var keyval = data[i].splitEx('=');            if (keyval.length < 2) continue;            var key = keyval.shift(), val = keyval.join('=');            if (key.unify() == item.unify()) {                if (del) data.splice(i, 1);                else {                    data[i] = item + '=' + value;                    WSH.Echo(value.trim());                }                saveAndQuit();            }        }        if (del) fatal(item + ' not found in ' + inifile);        data.cram(item + '=' + value);        WSH.Echo(value.trim());        saveAndQuit();    }}else if (section) { // and if (!modify)    for (var i=0; i<data.length; i++) {        if (data[i].unify() == section.unify()) {            for (var j=i + 1; j<data.length; j++) {                if (/^\s*\[.+\]\s*$/.test(data[j])) fatal(item + ' not found in ' + section + ' in ' + inifile);                var keyval = data[j].splitEx('=');                if (keyval.length < 2) continue;                var key = keyval.shift(), val = keyval.join('=');                if (key.unify() == item.unify()) {                    WSH.Echo(val.trim());                    WSH.Quit(0);                }            }        }    }    fatal(section + ' not found in ' + inifile);}else { // if (item) and nothing else    for (var i=0; i<data.length; i++) {        var keyval = data[i].splitEx('=');        if (keyval.length < 2) continue;        var key = keyval.shift(), val = keyval.join('=');        if (key.unify() == item.unify()) {            WSH.Echo(val.trim());            WSH.Quit(0);        }    }    fatal(item + ' not found in ' + inifile);}

ini.bat usage screen


I have short proposition for read config.ini file in current directory form windows batch (.bat):

Near end of batch file we paste that code:

:ini    @for /f "tokens=2 delims==" %%a in ('find "%~2=" "%~1"') do @set %~3=%%a    @goto:eof

And near start of batch file we call it by:

@call:ini "config.ini" IniFieldName batchVarName@echo IniFieldName is: %batchVarName%