Windows batch script pour lire an.fichier ini

j'essaie de lire un fichier .ini avec le format suivant:

[SectionName]
total=4
[AnotherSectionName]
total=7
[OtherSectionName]
total=12

fondamentalement, je veux imprimer certaines valeurs du fichier .ini , par exemple le total sous OtherSectionName suivi du total de AnotherSectionName .

21
demandé sur zb226 2010-05-19 17:55:53

7 réponses

voici un fichier de commande ( ini.cmd ) que vous pouvez utiliser pour extraire les valeurs pertinentes:

@setlocal enableextensions enabledelayedexpansion
@echo off
set file=%~1
set area=[%~2]
set key=%~3
set 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

et voici une transcription la montrant en action (j'ai indenté manuellement la sortie pour la rendre plus facile à lire):

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

pour l'utiliser réellement dans un autre fichier cmd , il suffit de remplacer la ligne echo %val% ci-dessous avec ce que vous voulez en faire):

for /f "delims=" %%a in ('call ini.cmd ini.ini AnotherSectionName total') do (
    set val=%%a
)
echo %val%
41
répondu paxdiablo 2012-11-02 16:47:28

je sais que je suis un peu en retard à la fête, mais j'ai décidé d'écrire un script de lot d'utilitaire de fichier ini à usage général pour répondre à cette question.

le script vous permettra de récupérer ou modifier des valeurs dans un fichier de style ini. Ses recherches sont insensibles à la casse, et il conserve les lignes vierges dans le fichier ini. Essentiellement, il vous permet d'interagir avec un fichier ini comme une sorte de base de données très rudimentaire.

ce script fonctionnera très bien si vous êtes lecture / écriture seulement valeurs ou Symboles alphanumériques qui n'ont pas de signification particulière pour l'interpréteur cmd . Si vous avez besoin de quelque chose capable de manipuler des valeurs contenant des Ampli, des percents, etc, voir la section mise à jour ci-dessous.

:: --------------------
:: ini.bat
:: ini.bat /? for usage
:: --------------------

@echo off
setlocal enabledelayedexpansion

goto begin

:usage
echo Usage: %~nx0 /i item [/v value] [/s section] inifile
echo;
echo Take the following ini file for example:
echo;
echo    [Config]
echo    password=1234
echo    usertries=0
echo    allowterminate=0
echo;
echo To read the "password" value:
echo    %~nx0 /s Config /i password inifile
echo;
echo To change the "usertries" value to 5:
echo    %~nx0 /s Config /i usertries /v 5 inifile
echo;
echo In the above examples, "/s Config" is optional, but will allow the selection of
echo a specific item where the ini file contains similar items in multiple sections.
goto :EOF

:begin
if "%~1"=="" goto usage
for %%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 usage
if 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

exemple

contenu de 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

session D'essai:

C:\Users\me\Desktop>ini /s AnotherSectionName /i total example.ini
7

C:\Users\me\Desktop>ini /s othersectionname /i Total /v f00 example.ini
f00

C:\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

mise à Jour

apparemment, la pur discontinu solution étouffe quand elle rencontre des caractères comme & (et probablement % et d'autres). Voici donc un script hybride batch + JScript plus robuste qui résout ce problème. La syntaxe et la sortie sont les mêmes (mais avec un commutateur /d ajouté pour supprimer les paires item=value ).

ce script définit %ERRORLEVEL%=0 pour succès, et %ERRORLEVEL%=1 sur erreur.

@if (@a==@b) @end /* -- batch / JScript hybrid line to begin JScript comment

:: --------------------
:: ini.bat
:: ini.bat /? for usage
:: --------------------

@echo off
setlocal enabledelayedexpansion

goto begin

:: color code by jeb -- https://stackoverflow.com/a/5344911/1683264
:c
set "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

:usage
for /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=1234
echo    usertries=0
echo    allowterminate=0
echo;
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 :s
call :c 0F "s Config "
echo is optional, but will allow the selection of
echo a specific item where the ini file contains similar items in multiple sections.
del X
goto :EOF

:begin
if "%~1"=="" goto usage
for %%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 usage
if 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 edges
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/,'') }

// trim + toLowerCase
String.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,){return });
    };
    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

20
répondu rojo 2017-05-23 11:54:44

j'ai une courte proposition pour Read config.fichier ini dans le répertoire courant de Windows batch (.chauve-souris):

près de fin de fichier de lot nous coller ce code:

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

et près du début du fichier de lot nous l'appelons par:

@call:ini IniFieldName batchVarName
@echo IniFieldName is: %batchVarName%
5
répondu emil 2010-12-23 11:00:56

config.ini

foo=string
bar=123
baz=spaces work too!

windows_batch.cmd

for /F "tokens=*" %%I in (config.ini) do set %%I
4
répondu grokster 2014-05-13 15:30:40

Voici le document. Espérons que cela aide!

1
répondu mosg 2010-05-19 14:06:47

vieille question mais j'en avais besoin récemment et j'ai trouvé la réponse à @paxdiablo. J'avais besoin de quelque chose de plus, alors j'ai enrichi sa réponse et je donne maintenant en retour.

ce dont j'avais aussi besoin, c'était de trouver quelle clé avait une valeur spécifique. Aussi, soutenez explicitement la section racine (aucun nom de section).

Voici mon code, une fonction que j'ai mise dans une bibliothèque (variable CMDLib) que j'appelle quand j'en ai besoin (entre autres fonctions).

:ReadINI
REM ReadINI - Get value from [Section]; Key from an INI File.
REM Arguments:
REM   File    INI-file to read from
REM   Key     Name of the entry
REM   Section Name of the [Section] under which the Value is.
REM     Optional, will find a value from the root section if empty.
REM               For root section, set to "-" to also use "Value"
REM   Value   If Key is set to "-", will find which Key has "Value"
REM
REM Returns: A string of text will be echoed, ready for logging.
REM   An echo of the value.
REM
REM Call example:
REM   for /f "delims=" %%a in ('Call "%CMDLib%" ReadINI "Inifile" Key Section') do ( set Value=%%a)
REM
REM Original: http://stackoverflow.com/a/2866328/151152
rem ------- Function header -------
    Setlocal ENABLEDELAYEDEXPANSION
    :: Logging formatting
    if not defined nest (set /a nest=0) else set /a Nest=%nest%+1
    if %nest% GEQ 1 if not defined _tab (set _tab=    ) else for /l %%i in (0, %nest%,1) do set _tab=%_tab%    
rem ------- Function body -------
    set file=%~1
    set key=%~2
    set Section=[%~3]
    if "%Section%"=="-" set Section=
    set value=%~4
    set currSection=
    Set RC=0
    for /f "usebackq delims=" %%a in ("%file%") do (
        set ln=%%a
        if "x!ln:~0,1!"=="x[" (
            set currSection=!ln!
        ) else (
            for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
                set currkey=%%b
                set currval=%%c
                if /i "x!Section!"=="x!currSection!" (
                    if /i "x!key!"=="x!currkey!" (
                        echo !currval!
                        if %_D% GEQ 2 echo %_tab%[%0 - RC:%RC%]
                        exit /b %RC%
                    ) Else if "x!key!"=="x-" (
                        if /i "x!value!"=="x!currval!" (
                            echo !currkey!
                            if %_D% GEQ 2 echo %_tab%[%0 - RC:%RC%]
                            exit /b %RC%
                        )
                    )
                )
            )
        )
    )
    if %_D% GEQ 2 echo %_tab%[%0 - RC:%RC%]
    Exit /b %RC%
rem ------- Function end -------

Pas de mise en évidence de la syntaxe pour CMD? C'est une honte.. ;- )

Espérons que cela aide les autres.

1
répondu Jay 2015-05-04 12:30:59

hmm, peut-être que ça aide quelqu'un.. A dû le construire depuis inifile.exe est à court d'astuces et semble que chaque fichu analyseur ini sur le web a besoin de " clé " alors que tout ce dont j'ai besoin est toutes les valeurs sous [section]. Voici l'empreinte de la section..

@echo off
SETLOCAL DisableDelayedExpansion
IF "%1"=="" (echo Usage: section input.ext output.ext & goto eof )
IF "%2"=="" (echo Usage: section input.ext output.ext & goto eof )
IF NOT EXIST "%2" (echo File does not exist. Usage: section input.ext output.ext & goto eof )
IF "%3"=="" (echo Usage: section input.ext output.ext & goto eof )
FOR /F "tokens=*" %%A IN ('findstr /I /N "\[.*\]" %2') DO (echo %%A>>LINE_START.DAT)
FOR /F "tokens=1,2 delims=:" %%A IN ('findstr /I "\[%1\]" LINE_START.DAT') DO (
SETLOCAL EnableDelayedExpansion
set FIRSTLINE=%%A
)
set /a "FIRSTLINE+=1"
FOR /F "tokens=1,2* delims=:" %%A IN ('findstr /I /N ".*" %2') DO (
IF %%A GEQ !FIRSTLINE! (echo %%B>>LINE_END.DAT)
)
set ENDLINE=500
FOR /F "tokens=1,2* delims=:" %%A IN ('findstr /I /N "\[.*\]" LINE_END.DAT') DO (
IF %%A LSS !ENDLINE! (set /a "ENDLINE=%%A") ELSE echo %%A>nul
)
set /a "ENDLINE-=1"
FOR /F "tokens=1,2* delims=:" %%A IN ('findstr /I /N ".*" LINE_END.DAT') DO (
IF %%A LEQ !ENDLINE! (echo %%B>>%3) ELSE ENDLOCAL
)
set ENDLINE=0
set FIRSTLINE=0
ENDLOCAL
DEL /Q LINE_*.DAT
:end

Ouais, ouais je sais qu'il semble que c'est de l'arrière, mais il fonctionne, bien que, pas sûr qu'il fonctionnera avec des espaces dans le dossier ou des espaces dans les fichiers. Construit fondamentalement juste .fichier ini dans le même dossier et exécuté depuis la ligne de commande.

Usage: genetix_ini.entrée de la section cmd.sortie en ext.poste 151920920"

mise à jour n ° 2: On dirait que j'ai fait une erreur en ne mettant pas à zéro les 2 ensembles de var. Ce qui a commencé à causer un problème au second passage du script.

0
répondu genetix 2013-09-07 03:32:01