Script por lotes de Windows para leer un archivo.ini
batch-file cmd (7)
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%
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
.
Hmm, tal vez esto ayude a alguien ... Tuve que compilarlo 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.
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 sintaxis 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://.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,$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);
}
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%
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://.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 sintaxis para CMD? Es una pena.. ;-)
Espero que esto ayude a otros también.
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!