Пакет Windows script для чтения файла .ini
Я пытаюсь прочитать файл .ini
со следующим форматом:
[SectionName]
total=4
[AnotherSectionName]
total=7
[OtherSectionName]
total=12
В основном я хочу распечатать определенные значения из файла .ini
, например, итоговое значение в OtherSectionName
, за которым следует итоговое значение от AnotherSectionName
.
Ответы
Ответ 1
Здесь командный файл (ini.cmd
) вы можете использовать для извлечения соответствующих значений:
@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
И здесь транскрипция, показывающая его в действии (я вручную отступом вывод, чтобы сделать его легче читать):
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
Чтобы использовать это в другом файле cmd
, просто замените строку echo %val%
ниже тем, что вы хотите с ней сделать):
for /f "delims=" %%a in ('call ini.cmd ini.ini AnotherSectionName total') do (
set val=%%a
)
echo %val%
Ответ 2
Я знаю, что немного опаздываю на вечеринку, но я решил написать общий пакет служебных файлов ini script для решения этого вопроса.
script позволит вам получить или изменить значения в файле ini-стиля. Его поиск не зависит от регистра, и он сохраняет пустые строки в ini файле. По сути, он позволяет вам взаимодействовать с ini файлом в виде очень простой базы данных.
Этот script будет работать нормально, если вы читаете/записываете только буквенно-цифровые значения или символы, которые не имеют особого значения для интерпретатора cmd
. Если вам нужно что-то, способное обрабатывать значения, содержащие амперсанды, проценты и т.д., См. Раздел Обновить ниже.
:: --------------------
:: 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
Пример
Содержание 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
Тестовый сеанс:
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
Update
По-видимому, чистое пакетное решение дросселирует, когда оно встречает символы типа &
(и, вероятно, %
и другие). Итак, здесь более надежный пакетный + JScript-гибрид script, который решает эту проблему. Синтаксис и вывод одинаковы (но с добавленным переключателем /d
для удаления пар item=value
).
Этот script устанавливает %ERRORLEVEL%=0
для успеха и %ERRORLEVEL%=1
при ошибке.
@if (@[email protected]) @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,$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]()
Ответ 3
У меня есть короткое предложение для чтения файла config.ini в текущей форме каталога windows batch (.bat):
В конце конца командного файла мы вставляем этот код:
:ini
@for /f "tokens=2 delims==" %%a in ('find "%~1=" config.ini') do @set %~2=%%a
@goto:eof
И около начала командного файла мы вызываем его:
@call:ini IniFieldName batchVarName
@echo IniFieldName is: %batchVarName%
Ответ 4
config.ini
foo=string
bar=123
baz=spaces work too!
windows_batch.cmd
for /F "tokens=*" %%I in (config.ini) do set %%I
Ответ 5
Вот документ. Надеюсь, это поможет!
Ответ 6
Старый вопрос, но я совсем недавно нуждался в этом и нашел @paxdiablo ответ.
Мне нужно было что-то еще, поэтому я обогатил его ответ, и теперь я возвращаюсь.
То, что мне также нужно, это найти, какой ключ имел определенную ценность.
Кроме того, явная поддержка корневого раздела (без названия раздела).
Здесь мой код, функция, которую я поместил в библиотеку (переменная CMDLib), я вызываю, когда мне это нужно (среди других функций).
: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 -------
Нет подсветки синтаксиса для CMD? Это позор..; -)
Надеюсь, это поможет и другим.
Ответ 7
Хм, может быть, это помогает кому-то. Надо было его построить, так как inifile.exe вышло из трюков и кажется, что каждый проклятый ini-парсер в Интернете нуждается в "KEY", когда все, что мне нужно, это все значения в разделе [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
Да, да, я знаю, что он выглядит сзади, но он работает, хотя, не уверен, что он будет работать с пробелами в папке или пробелах в файлах. Построил его, чтобы в основном иметь файл .ini в той же папке и запускался из командной строки.
Использование: genetix_ini.cmd раздел input.ext output.ext
ОБНОВЛЕНИЕ # 2:
Кажется, я ошибся, не обнуляя 2 набора варов. Что вызвало проблему при втором проходе script.