簡體   English   中英

Windows批處理文件-在文件中查找字符串並將其追加

[英]Windows Batch File - Find String In File And Append To It

所以我非常接近我想要達到的目標,但是我似乎無法超越我目前所堅持的觀點。

首先,我有一個.ini文件,該文件具有標題以及用逗號分隔的項目列表:

[Items]
ListOfItems = Item01, Item02, Item03

我需要做的是找到該特定部分( ListOfItems ),並向其添加參考文件中不存在的新項目。

這是我到目前為止的內容:

SET /P NewItem=
SET ListOfItems=
FOR /F delims^=^"^ tokens^=2 %%G IN ('type File.ini') DO  (set ListOfItems=%%G)
echo ListOfItems ^=^"%ListOfItems%, %NewItem%^">File.ini

我遇到的問題是,我使用提示而不是從文件( List.txt )中換行,因為上次我嘗試反復不斷重復同一行,而不是只重復一行,如果它不是重復的。

我遇到的另一個問題是,使用上面的當前代碼,它不會保留.ini文件的當前狀態。 因此,您可以按照上面的示例操作,但是一旦通過提示符添加新項目,您最終會得到:

ListOfItems =", Item04"

標頭不見了,原始值不見了,它以逗號開頭,而不是僅在每個值后面添加逗號。

因此,預期結果是:

[Items]
ListOfItems = Item01, Item02, Item03, Item04

為什么在第一次運行時不保留原始數據,但隨后的運行卻完美地復制了原始數據並添加到原始數據中?

我們如何解決這個問題,以逗號開頭,前面沒有數據?

我們如何才能從List.txt中提取要追加的項目列表,而不是一次手動輸入一項?

編輯:我已經設法解決以下第二個問題:

(
    ECHO [Items]
    ECHO !ArchiveList! = !RequiredItems!
)>>File.ini

!RequiredItems! 包含基礎項Item01, Item02, Item03 ,這些項在按照John Kens的建議未填充ListOfItems時執行。

至於第三個問題,我通過以下方法解決了:

FOR /F "delims=" %%A IN (List.txt) DO (
    SET "ListAddition=!ListAddition!%%A, "
)
SET "ListAddition=!ListAddition:~0,-2!"

它將List.txt文件中的每一項都放在新行上,然后將其添加到列表中,每一項之間用逗號分隔。

首先,您需要對當前的for loop一些調整。 我們可以在這里做一些事情。 如果我們只是想從第二行中獲取ListOfItems等於什么,而忽略了此文件中可能還有其他對象的事實,那么獲取此數據的正確方法如下:

FOR /F "skip=1 tokens=2,*" %%A IN ('type File.ini') DO (set "ListOfItems=%%B")
  • skip=1 -將跳過該第一線
  • tokens=2,* -具有2,*將導致%%A是前兩個對象, %%B將是2之后的所有對象。

但是,為了更適當,正確的方法將是使用find /i語句在.ini文件中查找ListOfItems對象。 讓我們來看下面的文本文件:

[Items]
ListOfItems = Item01, Item02, Item03
[Armor]
ListOfArmor = Iron Helmet, Iron Brestplate, Iron Pants
[Weapons]
ListOfWeapons = Sword, Dagger, Holy Water

如果在此語句上使用該基本的for循環,則將獲得文本文件的最后一行:

Sword, Dagger, Holy Water

貝婁將find語句與另一個循環一起使用,我們可以將它們組合在一起,僅從整個文檔中提取ListOfItems之后的數據。

Rem | Get .ini To String
FOR /F "tokens=*" %%A IN ('type File.ini') DO (

    Rem | Look For Line With Items "ListOfItems"
    FOR /F "tokens=2,*" %%B IN ('echo %%A^| find /i "ListOfItems"') DO (

        Rem | Echo Result
        echo %%C
    )
)

但是,對於僅校正那一行並在末尾添加新對象的地方,這很棘手! 請記住,批處理是原始的且缺乏支持,與它的后繼者powershell相比,它的局限性是有限的。 在原始批處理中,沒有真正的命令可以只編輯文檔中間的一行。 但是,這並非不可能。

為了解決這個問題,我們將需要獲取整個.ini文件,並使用type命令逐行分解文檔並將其保存為字符串。 在這里,我們可以使用語法替換來編輯“字符串”並將其保存到新文檔中。 從那里,我們只是刪除並重命名。

為了進一步擴展,我們將需要檢查ListOfItems是否實際填充。 基本的if exists語句將在這里很好地工作。 現在,由於您的語句的等式中有= ,因此如果沒有進一步的復雜性,簡單的syntax-replace將無法工作。 在之前的編輯中,我將簡單函數更改為我們也將call的腳本。 該腳本將稱為Replace.bat 您需要做的就是制作一個新的.bat文件,並將其粘貼到波紋管中。 該文件將永遠不需要修改。

貝婁是應該解決您所有問題的整個項目:

Replace.Bat:

(整個腳本等效於powershell lol中的一個15個字符的命令!)

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "FILE_I=%~1"
set "SEARCH=%~2"
set "REPLAC=%~3"
set "FILE_O=%~4"
set "FLAG=%~5"
if not defined FILE_I exit /B 1
if not defined SEARCH exit /B 1
if not defined FILE_O set "FILE_O=con"
if defined FLAG set "FLAG=#"

for /F "delims=" %%L in ('
    findstr /N /R "^" "%FILE_I%" ^& break ^> "%FILE_O%"
') do (
    set "STRING=%%L"
    setlocal EnableDelayedExpansion
    set "STRING=!STRING:*:=!"
    call :REPL RETURN STRING SEARCH REPLAC %FLAG%
    >> "%FILE_O%" echo(!RETURN!
    endlocal
)

endlocal
exit /B


:REPL  rtn_string  ref_string  ref_search  ref_replac  flag
setlocal EnableDelayedExpansion
set "STR=!%~2!"
set "SCH=!%~3!"
set "RPL=!%~4!"
if not defined SCH endlocal & set "%~1=" & exit /B 1
set "SCH_CHR=!SCH:~,1!"
if not "%~5"=="" set "SCH_CHR="
if "!SCH_CHR!"=="=" set "SCH_CHR=" & rem = terminates search string
if "!SCH_CHR!"==""^" set "SCH_CHR=" & rem " could derange syntax
if "!SCH_CHR!"=="%%" set "SCH_CHR=" & rem % ends variable expansion
if "!SCH_CHR!"=="^!" set "SCH_CHR=" & rem ! ends variable expansion
call :LEN SCH_LEN SCH
call :LEN RPL_LEN RPL
set /A RED_LEN=SCH_LEN-1
set "RES="
:LOOP
call :LEN STR_LEN STR
if not defined STR goto :END
if defined SCH_CHR (
    set "WRK=!STR:*%SCH_CHR%=!"
    if "!WRK!"=="!STR!" (
        set "RES=!RES!!STR!"
        set "STR="
    ) else (
        call :LEN WRK_LEN WRK
        set /A DFF_LEN=STR_LEN-WRK_LEN-1,INC_LEN=DFF_LEN+1,MOR_LEN=DFF_LEN+SCH_LEN
        for /F "tokens=1,2,3 delims=," %%M in ("!DFF_LEN!,!INC_LEN!,!MOR_LEN!") do (
            rem set "RES=!RES!!STR:~,%%M!"
            if defined WRK set "WRK=!WRK:~,%RED_LEN%!"
            if "!STR:~%%M,1!!WRK!"=="!SCH!" (
                set "RES=!RES!!STR:~,%%M!!RPL!"
                set "STR=!STR:~%%O!"
            ) else (
                set "RES=!RES!!STR:~,%%N!"
                set "STR=!STR:~%%N!"
            )
        )
    )
) else (
    if "!STR:~,%SCH_LEN%!"=="!SCH!" (
        set "RES=!RES!!RPL!"
        set "STR=!STR:~%SCH_LEN%!"
    ) else (
        set "RES=!RES!!STR:~,1!"
        set "STR=!STR:~1!"
    )
)
goto :LOOP
:END
if defined RES (
    for /F delims^=^ eol^= %%S in ("!RES!") do (
        endlocal
        set "%~1=%%S"
    )
) else endlocal & set "%~1="
exit /B


:LEN  rtn_length  ref_string
setlocal EnableDelayedExpansion
set "STR=!%~2!"
if not defined STR (set /A LEN=0) else (set /A LEN=1)
for %%L in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
    if defined STR (
        set "INT=!STR:~%%L!"
        if not "!INT!"=="" set /A LEN+=%%L & set "STR=!INT!"
    )
)
endlocal & set "%~1=%LEN%"
exit /B

Main.Bat:

@ECHO OFF
@setlocal EnableDelayedExpansion

Rem | Configuration
set "CustomINI=File.ini"
set "ListHeader=[Items]"
set "Object=ListOfItems"
set "ReplaceScript=Replace.bat"
SET "ItemList=List.txt"

Rem | Check If "CustomINI" Exists
if not exist "%CustomINI%" (
    echo File "%CustomINI%" Not Found!
    pause
    goto :EOF
)

Rem | Check If "ItemList" Exists
if not exist "%ItemList%" (
    echo File "%ItemList%" Not Found!
    pause
    goto :EOF
)
goto StartFunction

:StartFunction

Rem | Generate the list of items from textfile
FOR /F "delims=" %%A IN (%ItemList%) DO (
    set "ListAddition=!ListAddition!%%A, "
)
set "ListAddition=!ListAddition:~0,-2!"

Rem | Get .ini To String
set HeaderFound=false
FOR /F "tokens=*" %%A IN ('type !CustomINI!') DO (

    Rem | First Find The Header "[Items]" & Extract "ListOfItems" Line Data
    for /f "tokens=*" %%B in ('echo %%A') do (
        set "item=%%B"
        if /i "!item!"=="!ListHeader!" (
            set HeaderFound=true
        ) else if not "!item!"=="!item:ListOfItems=!" if "!HeaderFound!"=="true" (

            Rem | Turn Items For Line "ListOfItems" To String
            for /f "tokens=2,*" %%C in ('echo %%B') do (

               Rem | Set String
               set "SEARCHTEXT=%%D"
            )
            set HeaderFound=false

        )
    )
)

Rem | Check If "ListOfItems" Is Actually Populated
If "%SEARCHTEXT%"=="" (
    Rem | Not Populated
    set "SEARCHTEXT=!Object! = "
    set "REPLACETEXT=!Object! = !ListAddition!"
    goto EditString
) ELSE (
    Rem | Populated
    set "REPLACETEXT=!SEARCHTEXT!, !ListAddition!"
    goto EditString
)

:EditString

Rem | Edit Only "ListOfItems" Line
Rem | Usage: call "1" "2" "3" "4" "5"
Rem | call - Calls external script
Rem | "1" - Name of External script
Rem | "2" - File to Edit
Rem | "3" - Text to replace ex: red apple
Rem | "4" - Text to replace to ex: green apple
Rem | "5" - Output file
call "%ReplaceScript%" "%CustomINI%" "%SEARCHTEXT%" "%REPLACETEXT%" "%CustomINI%.TEMP"

Rem | Delete Original File, Restore New
del "%CustomINI%"
rename "%CustomINI%.TEMP" "%CustomINI%"

goto :EOF

PS -請注意以下事項:上述腳本預計,當ListOfItems =沒有填充,因此它具有后空間= 如果這不是您的.ini文件中的方式,則在for語句中更改set "SEARCHTEXT=!OBJECT! = " set "SEARCHTEXT=!OBJECT! ="


編輯:由於最近的請求,以下已更新:

首先,由於我不確定OP的ListOfItems =的含義是“空白”,因此我假設他/她所指的是ListOfItems = -不是它實際上從ListHeader丟失了ListHeader 在下面的例子中。

我的視野-File.ini:

[Items]
ListOfItems = 
[Armor]
ListOfArmor = Iron Helmet, Iron Brestplate, Iron Pants
[Weapons]
ListOfWeapons = Sword, Dagger, Holy Water

OP的願景-File.ini

[Items]

[Armor]
ListOfArmor = Iron Helmet, Iron Brestplate, Iron Pants

[Weapons]
ListOfWeapons = Sword, Dagger, Holy Water

從那時起,我現在更新了腳本以查找[Items] (字符串),然后在其下添加新行。 這是使用Magoo的腳本完成的。

由於沒有什么可替換的,因此我們只需將“ .ini ”添加到.ini從而調用其他函數。

:EditMissingString

Rem | Export SearchString
echo !ListHeader!>> %~dp0ListHeader.txt

Rem | Add Text Under %ListHeader%
(
    FOR /f "delims=" %%i IN (ListHeader.txt) DO (
    SET AddAfter=%%i

    FOR /f "delims=" %%n IN ('findstr /n "^" %CustomINI%') DO (
        SET line=%%n
        SET line=!line:*:=!

        ECHO(!line!
            IF "!line!"=="!AddAfter!" ECHO(%AddTEXT%
        )
    )
)>>%CustomINI%.TEMP

Rem | Remove ListHeader.txt
DEL %~dp0ListHeader.txt

Rem | Delete Original File, Restore New
DEL %CustomINI%
REN %CustomINI%.TEMP %CustomINI%

goto :EOF

由於我們不再單獨編輯ListOfArmor = ,而是添加到列表中,因此我們不再需要Replace.bat腳本。 我還修復了原始腳本以正確保留空行!

新的替換功能W / H線路保留。

:EditExistingString

REM | Make sure we only edit the ListOfItems line.
FOR /F "delims=" %%n IN ('findstr /n "^" %CustomINI%') DO (
    SET line=%%n
    SET Modified=!line:%SearchText%=%ReplaceText%!
    SET Modified=!Modified:*:=!

    REM | Output the entire edited INI to a temporary file.
    >> %CustomINI%.TEMP ECHO(!Modified!
)

Rem | Delete Original File, Restore New
DEL %CustomINI%
REN %CustomINI%.TEMP %CustomINI%

goto :EOF

造成:

[Items]
ListOfItems = Item1, Item2, Item3

[Armor]
ListOfArmor = Iron Helmet, Iron Brestplate, Iron Pants

[Weapons]
ListOfWeapons = Sword, Dagger, Holy Water

結果輸出:

[Items]
ListOfItems = Item1, Item2, Item3, Item4, Item5, Item6

[Armor]
ListOfArmor = Iron Helmet, Iron Brestplate, Iron Pants

[Weapons]
ListOfWeapons = Sword, Dagger, Holy Water

最終批處理腳本:

@ECHO OFF
@setlocal EnableDelayedExpansion

Rem | Configuration
set "CustomINI=File.ini"
set "ListHeader=[Items]"
set "Object=ListOfItems"
SET "ItemList=List.txt"

Rem | Check If "CustomINI" Exists
if not exist "%CustomINI%" (
    echo File "%CustomINI%" Not Found!
    pause
    goto :EOF
)

Rem | Check If "ItemList" Exists
if not exist "%ItemList%" (
    echo File "%ItemList%" Not Found!
    pause
    goto :EOF
)
goto StartFunction

:StartFunction

Rem | Generate the list of items from textfile
FOR /F "delims=" %%A IN (%ItemList%) DO (
    set "ListAddition=!ListAddition!%%A, "
)
if "%ListAddition%"=="" (
    echo ERROR: File "%ItemList%" Is Empty!
    pause
    goto :EOF
) ELSE (set "ListAddition=!ListAddition:~0,-2!")

Rem | Get .ini To String
set HeaderFound=false
FOR /F "tokens=*" %%A IN ('type !CustomINI!') DO (

    Rem | First Find The Header "[Items]" & Extract "ListOfItems" Line Data
    for /f "tokens=*" %%B in ('echo %%A') do (
        set "item=%%B"
        if /i "!item!"=="!ListHeader!" (
            set HeaderFound=true
        ) else if "!HeaderFound!"=="true" (

            Rem | Turn Items For Line "ListOfItems" To String
            for /f "tokens=2,*" %%C in ('echo %%B') do (

               Rem | Set String
               set "SearchText=%%D"
            )
            Rem | Header Was Found, End Loop & goto HeaderContinue
            set HeaderFound=false
            goto HeaderContinue
        )

    )
)
Rem | Header Was Not Found
echo ERROR: The Header "%ListHeader%" Was Not Found!
pause
goto :EOF

:HeaderContinue

Rem | Check If "ListOfItems" Is Actually Populated
If "%SearchText%"=="" (
    Rem | Not Populated
    set "SearchText=!ListHeader!"
    set "AddTEXT=!Object! = !ListAddition!"
    goto EditMissingString
) ELSE (
    Rem | Populated
    set "REPLACETEXT=!SearchText!, !ListAddition!"
    goto EditExistingString
)

:EditExistingString

REM | Make sure we only edit the ListOfItems line.
FOR /F "delims=" %%n IN ('findstr /n "^" %CustomINI%') DO (
    SET line=%%n
    SET Modified=!line:%SearchText%=%ReplaceText%!
    SET Modified=!Modified:*:=!

    REM | Output the entire edited INI to a temporary file.
    >> %CustomINI%.TEMP ECHO(!Modified!
)

Rem | Delete Original File, Restore New
DEL %CustomINI%
REN %CustomINI%.TEMP %CustomINI%

goto :EOF

:EditMissingString

Rem | Add Text Under %ListHeader%
(
    FOR /f "delims=" %%i IN ('Echo !ListHeader!') DO (
    SET AddAfter=%%i

    FOR /f "delims=" %%n IN ('findstr /n "^" %CustomINI%') DO (
        SET line=%%n
        SET line=!line:*:=!

        ECHO(!line!
            IF "!line!"=="!AddAfter!" ECHO(%AddTEXT%
        )
    )
)>>%CustomINI%.TEMP

Rem | Delete Original File, Restore New
DEL %CustomINI%
REN %CustomINI%.TEMP %CustomINI%

goto :EOF

PS:我知道您的find命令位於其他位置,或者只是將命令find更改為腳本中的%WINDIR%\\System32\\FIND.exe

DEBUG /變更:

刮掉。


要獲得有關任何命令的幫助,請執行以下操作:

  • call /?
  • set /?
  • for /?
  • if /?
  • find /?
  • 等等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM