Script por lotes de Windows para leer un archivo .ini

Estoy tratando de leer un archivo .ini con el siguiente formato:

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

Básicamente, quiero imprimir ciertos valores del archivo .ini , por ejemplo, el total en OtherSectionName seguido del total de AnotherSectionName .

Aquí hay un archivo de comando ( ini.cmd ) que puede usar para extraer los valores relevantes:

 @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 

Y aquí hay una transcripción que lo muestra en acción (He sangrado manualmente la salida para que sea más fácil de leer):

 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 

Para usar esto en otro archivo cmd , simplemente reemplace la línea echo %val% continuación con lo que quiera hacer con él):

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

Sé que llegué un poco tarde a la fiesta, pero decidí escribir una secuencia de comandos de lote de utilidades de archivos ini para abordar esta pregunta.

La secuencia de comandos le permitirá recuperar o modificar valores en un archivo de estilo ini. Sus búsquedas no distinguen entre mayúsculas y minúsculas y conserva las líneas en blanco en el archivo ini. En esencia, le permite interactuar con un archivo ini como una especie de base de datos muy rudimentaria.

Esta secuencia de comandos funcionará bien si está leyendo / escribiendo solo valores alfanuméricos o símbolos que no tienen un significado especial para el intérprete de cmd . Si necesita algo capaz de manejar valores que contengan símbolos, porcentajes, etc., consulte la sección Actualizar a continuación.

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

Ejemplo

Contenido 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 

Sesión de prueba:

 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 

Actualizar

Aparentemente, la solución de lote puro se ahoga cuando encuentra caracteres como & (y probablemente % y otros). Así que aquí hay una secuencia de comandos híbrida masiva por lotes + JScript que resuelve ese problema. La syntax y el resultado son los mismos (pero con un modificador /d para eliminar item=value pares de item=value ).

Este script establece %ERRORLEVEL%=0 para el éxito, y %ERRORLEVEL%=1 en caso de error.

 @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  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) || []; i0 && !this[--i].length) {}; for (var j=0; j 

pantalla de uso de ini.bat

Tengo una propuesta breve para leer el archivo config.ini en el formulario actual del lote de windows (.bat):

Cerca del final del archivo por lotes, pegamos ese código:

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

Y cerca del inicio del archivo por lotes lo llamamos por:

 @call:ini IniFieldName batchVarName @echo IniFieldName is: %batchVarName% 

config.ini

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

windows_batch.cmd

 for /F "tokens=*" %%I in (config.ini) do set %%I 

Aquí está el documento. ¡Espero eso ayude!

Una vieja pregunta, pero recientemente lo necesitaba y encontré la respuesta de @paxdiablo. Necesitaba algo más, así que enriquecí su respuesta y ahora estoy devolviendo.

Lo que también necesitaba era encontrar qué tecla tenía un valor específico. Además, admite explícitamente la sección raíz (sin nombre de sección).

Aquí está mi código, una función que pongo en una biblioteca (variable CMDLib) a la que llamo cuando la necesito (entre otras funciones).

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

Sin resaltado de syntax para CMD? Es una pena.. 😉

Espero que esto ayude a otros también.

Hmm, tal vez esto ayude a alguien … Tuve que comstackrlo ya que inifile.exe se quedó sin trucos y parece que cada maldito analizador de ini en la web necesita ‘KEY’ cuando todo lo que necesito son todos los valores en [section]. Entonces, aquí está la impresión de la sección.

 @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 

Sí, sí, sé que parece ser desde atrás, pero funciona, aunque no estoy seguro de que funcione con espacios en la carpeta o espacios en los archivos. Creado básicamente para tener solo el archivo .ini en la misma carpeta y ejecutado desde la línea de comandos.

Uso: sección genetix_ini.cmd input.ext output.ext

ACTUALIZACIÓN # 2: Parece, cometí un error al no poner a cero los 2 set vars. Que comenzó a causar un problema en el segundo pase del guión.