我正在尝试使用以下格式读取.ini
文件:
[SectionName] total=4 [AnotherSectionName] total=7 [OtherSectionName] total=12
基本上我想打印出.ini
文件中的某些值,例如OtherSectionName
下的总数,然后是OtherSectionName
的总数。
这里有一个命令文件( 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%
我知道我晚了一点,但我决定写一个通用的ini文件实用程序批处理脚本来解决这个问题。
该脚本将允许您检索或修改ini样式的文件中的值。 它的搜索不区分大小写,并保留ini文件中的空白行。 实质上,它允许你作为一种非常基本的数据库与一个ini文件进行交互。
如果您只读取/写入字母数字值或对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
显然, 纯粹的批处理解决方案在遇到像&
(也许是%
和其他)这样的字符时会窒息 。 所以这里有一个更强大的batch + JScript混合脚本来解决这个问题。 语法和输出是相同的(但添加/d
开关删除item=value
对)。
这个脚本为成功设置%ERRORLEVEL%=0
,错误时为%ERRORLEVEL%=1
。
@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,$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); }
我有一个简短的命题来读取当前目录窗体批处理(.bat)中的config.ini文件:
在批处理文件的结尾我们贴上这个代码:
: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%
config.ini文件
foo=string bar=123 baz=spaces work too!
windows_batch.cmd
for /F "tokens=*" %%I in (config.ini) do set %%I
这是文件。 希望能帮助到你!
老问题,但我最近需要,并发现@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? 这是一个遗憾.. 😉
希望这对其他人也有帮助。
嗯,也许这有助于人..不得不建立它,因为inifile.exe跑出了技巧,似乎每个该死的ini解析器上的网络需要'关键'时,我所需要的是所有值[部分]。 所以,这里是打印部分
@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集变量。 在脚本第二遍时就开始出现问题。