silvereye
Goto Top

Batch. Suchen und Ersetzen in einer Zeile einer ini-Datei die ein ! enthält

Moin zusammen,

In einer ini-Datei sind Sektionen mit Schlüssel-Wert-Paaren in der Form von:

[logging]
logfilecount=10
loggingactive=true
loglevel=DEBUG

[catalog]
catalogfilecount=10
catalogpath=catalog
activecatalog=catalog.bin

[naming]
activescheme=Personen.xml
autoscan=false
namingservercheck=false
useclassification=true

[fileparameter]
picfiles=jpg!bmp!tif!tiff!gif!
vidfiles=avi!mpeg!mpg!


…. usw. vorhanden.

Beim Programmstart wird vor der Verwendung der ini-Datei auf dem Netzlaufwerk nach geänderten Schlüssel-Wert-Paaren geschaut. Das klappt bis auf die Wertpaare, die ein ! enthalten. Die ! verschwinden leider nach dem Skriptdurchlauf und sehen dann so aus:

[fileparameter]
picfiles=jpgbmptiftiffgif
vidfiles=avimpegmpg


Kann mir hier jemand weiterhelfen?

Anbei mein Skript:
@echo off

setlocal enabledelayedexpansion

set "clientIniPath=C:\Programm\programm.ini"  
set "computerName=%COMPUTERNAME%"  
set "serverIniPath=\\Netzlaufwerk\%computerName%.ini"  

if exist "%serverIniPath%" (  
    echo Datei %serverIniPath% existiert.

    for /f "tokens=1* delims==" %%A in ('findstr /r /c:"=.*" "%serverIniPath%"') do (  
        set "serverKey=%%A"  
        set "serverValue=%%B"  
        set "found=0"  

        for /f "tokens=1* delims==" %%C in ('findstr /r /c:"=.*" "%clientIniPath%"') do (  
            if "%%C"=="!serverKey!" (  
                set "found=1"  
                if not "%%D"=="!serverValue!" (  
                    echo Wert für !serverKey! wird überschrieben.
                    call :replaceLine "%clientIniPath%" "%%C=%%D" "%%C=!serverValue!"  
                )
            )
        )

        if "!found!"=="0" (  
            echo !serverKey!=!serverValue! >> "%clientIniPath%"  
        )
    )
) else (
    echo Datei %serverIniPath% existiert nicht.
)

goto :eof

:replaceLine
set "file=%~1"  
set "search=%~2"  
set "replace=%~3"  
set "tempFile=%file%.tmp"  

(for /f "delims=" %%i in ('type "%file%"') do (  
    set "line=%%i"  
    if "!line!"=="%search%" (  
        echo %replace%
    ) else (
        if "!line:~0,1!"=="[" (  
            echo.
            echo %%i
        ) else (
            echo %%i
        )
    )
)) > "%tempFile%"  

move /y "%tempFile%" "%file%"  
goto :eof

pause

Content-ID: 93351255323

Url: https://administrator.de/forum/batch-suchen-und-ersetzen-in-einer-zeile-einer-ini-datei-die-ein-enthaelt-93351255323.html

Ausgedruckt am: 22.12.2024 um 06:12 Uhr

TK1987
TK1987 15.08.2024 aktualisiert um 10:21:19 Uhr
Goto Top
Moin,

wäre es nicht einfacher zu überprüfen, ob die ini auf dem Server anders ist und diese in dem Fall zu kopieren?

Zitat von @silvereye:
Das klappt bis auf die Wertpaare, die ein ! enthalten. Die ! verschwinden leider nach dem Skriptdurchlauf und sehen dann so aus:
Du musst in dem Fall natürlich auf das "setlocal EnableDelayedExpansion" verzichten und stattdessen mit Funktionen arbeiten.

Etwa so:
@echo off

set "clientIniPath=C:\Programm\programm.ini"  
set "serverIniPath=\\Netzlaufwerk\%computerName%.ini"  

if exist "%serverIniPath%" (  
    echo Datei %serverIniPath% existiert.

    for /f "tokens=1* delims==" %%A in ('findstr /r /c:"=.*" "%serverIniPath%"') do (  
        set found=0
        for /f "tokens=1* delims==" %%C in ('findstr /r /c:"=.*" "%clientIniPath%"') do call :checkKey "%%~A" "%%~B" "%%~C" "%%~D"  
        call :checkFound && >>"%clientIniPath%" echo %%~A=%%~B  
    )
) else echo Datei %serverIniPath% existiert nicht.
goto :eof

:checkKey <ServerKey> <ServerValue> <ClientKey> <ClientValue>
  if "%~3" == "%~1" (  
    set found=1
    if not "%~4" == "%~2" (    
      echo Wert für %~1 wird überschrieben.
      call :replaceLine "%clientIniPath%" "%~3=%~4" "%~3=%~2"    
    )
  )
  exit /b 0

:replaceLine
  set "file=%~1"  
  set "search=%~2"  
  set "replace=%~3"  
  set "tempFile=%file%.tmp"  

  >"%tempFile%" (for /f "delims=" %%i in ('type "%file%"') do call :checkLine "%%~i")  

  move /y "%tempFile%" "%file%"  
  goto :eof
  
:checkLine <line>
  set "line=%~1"  
  if "%line%"=="%search%" (  
      echo %replace%
  ) else (
      if "%line:~0,1%"=="[" (  
          echo.
          echo %~1
      ) else (
          echo %~1
      )
  )
  exit /b 0
  
:checkFound
  exit /b %found%

Gruß Thomas
silvereye
silvereye 15.08.2024 um 13:42:28 Uhr
Goto Top
Hallo TK1987,

vielen Dank für deine Antwort. Leider brachte Deine Lösung nicht den gewünschten Erfolg.

Beim Programmstart wird vor der Verwendung der ini-Datei „programm.ini“ auf dem Netzlaufwerk in der Datei „MEINPC123456.ini“ nach geänderten Schlüssel-Wert-Paaren geschaut.
In der Datei „MEINPC123456.ini“ sind Schlüssel-Wert-Paare enthalten, die in die „programm.ini“ an der gleichen Stelle aus der „MEINPC123456.ini“ übernommen werden sollen.
Das klappt auch alles mit meinem Skript bis auf die Werte die ein !-Zeichen enthalten.

Zum Testen habe ich noch einmal die Inhalte der beiden ini-Dateien als Text unten angehängt.

Hat jemand noch eine Idee?


Anbei zum Testen der Inhalt der "programm.ini" Datei:
[versuch]
defaultpath=C:\\Programmpfad\\Programm
naming=false
bmptexttrans=false

[logging]
logfilecount=10
loggingactive=true
loglevel=DEBUG

[katalog]
catalogfilecount=10
catalogpath=catalog
activecatalog=catalog.bin

[benennung]
scheme=Schema_Test_Preparation_20240525.xml
autonaming=false
namingserverpath=C:\\netzpfad\\naming
namingservercheck=false
useclassification=true

[global]
version=Testprogramm 2.1.2.30
defaultprogversion=1.6
fotofree=true
adminmode=false
adminpasswd=testpass123
fototab=true
movietab=true
reporttab=false
rohtab=true
othertab=true
oldnew=true
createmainfolder="Foto;Movie"
checkorientation=false
wksname=MEINPC123456
wksusername=MUSTERMANN
phorem=false
molrem=false
reprem=false
rohrem=false

[transfer]
apiserviceurl=https://wunschadresse.de
filenamecheck=true
photoactive=true
movieactive=true
rohactive=true
otheractive=false
reportactive=true
doubtransfer=false
nomovietransfer=true

[bildtext]
family=Arial
pointsize=48
weight=75
italic=false
imagetext=<Bildname>
fontcolor=#ffffff
bgcolor=#000000
textposition=0
vornach=true
dateiname=false
gammamemoryone=1.1
gammamemorytwo=1.3
gammamemorythree=1.5

[verteilt]
masterpath=-- Kein Master ausgew\xe4hlt --
slavepath
sharedactiv=false

[dateiparameter]
phofiles=jpg!bmp!tif!tiff!gif!
miifiles=avi!mpeg!mpg!
rohfiles=bay!cin!tif!tiff!fba!tp2!b16!mcf!
otherfiles=imh!mme!pho!mii!
repfiles=ses!inc!pc!txt!ids!
codecwhitelist=IV50.H264.X264.XVID

[tools]
toolchain

[options]
generalConf=true
loggingConf=false
catalogConf=false
fileFormatConf=true
toolConf=false
namingConf=true
shareTestConf=false
imageConf=true

und der Inhalt der "MEINPC123456.ini":
[benennung]
scheme=NEU_Schema_Test_Preparation_20240815.xml
useclassification=false

[transfer]
apiserviceurl=https://wunsch.de

[dateiparameter]
phofiles=jpg!bmp!tif!tiff!gif!biff!
miifiles=avi!mpeg!mpg!lex!

[options]
generalConf=true
loggingConf=false
TK1987
Lösung TK1987 15.08.2024 um 14:40:51 Uhr
Goto Top
Zitat von @silvereye:
Hat jemand noch eine Idee?
Die wie immer beste Idee hätte ich natürlich noch: Batch endlich begraben und stattdessen zeitgemäß Powershell nehmen...
$ClientFile = "C:\Programm\programm.ini"  
$ServerFile = "\\Netzlaufwerk\${ENV:ComputerName}.ini"  

function Read-Ini {
  [CmdletBinding()]Param([string]$path)
  
  $ini     = [ordered]@{}
  $section = ""  

  Foreach ($Line in Get-Content -Path $path) {
    switch -RegEx ($line) {
      "^\[(.+)\]$" {  
        $section = $Matches[1]
        $ini.$section = [ordered]@{}
      }
      "^([^=]+)=(.*)$" {  
        $key,$value = $Matches[1,2]
        $ini.$section.$key = $value
      }
      "^\s*$" {}  
      default {
        $ini.$section.$_ = $NULL
      }
    }
  }

  Add-Member -Input $ini -MemberType ScriptMethod -Name ToArray -Value {
    $content = Foreach ($section in $this.keys) {
      "[$section]"  
      Foreach ($e in $this.$section.GetEnumerator()) {
        if ($e.Value) {
          "{0}={1}" -f $e.Key,$e.Value  
        } else {$e.Key}
      }
      ""  
    }
    $content[0..($content.count-2)]
  }

  return $ini
}

try {
  $ErrorActionPreference = "stop"  
  $clientIni = Read-Ini $ClientFile
  $ServerIni = Read-Ini $ServerFile

  foreach ($section in $serverIni.keys) {
    if ($clientIni.keys -notcontains $section) {
      Write-Host "Ergänze Sektion: $section"  
      $clientIni.$section = $serverIni.$section
    }
    else {
      Foreach ($key in $serverIni.$section.keys) {
        if ($clientIni.$section.keys -notcontains $key) {
          Write-Host "Ergänze Schlüssel in [${section}]: $key"  
          $clientIni.$section.$key = $serverIni.$section.$key
        }
        else {
          if ($clientIni.$section.$key -ne $serverIni.$section.$key) {
            Write-Host "Ändere Wert für ${key}"  
            $clientIni.$section.$key = $serverIni.$section.$key
          }
        }
      }
    }
  }

  $clientIni.ToArray() | Set-Content $clientFile
} catch {
  Write-Host -ForegroundColor red $_.Exception.Message
  Write-Host -ForegroundColor yellow -NoNewLine "`n   ---   Beliebige Taste zum Beenden   ---   "  
  [void][Console]::ReadKey($true)
}
silvereye
silvereye 15.08.2024 um 15:22:06 Uhr
Goto Top
Hallo TK1987,

danke. Ich bekomme zu den zu ändernden Key-Values nicht die entsprechenden Values. Diese fehlen dann.

das Ergebnis sieht dann so aus:

[versuch]

defaultpath=C:\\Programmpfad\\Programm
naming=false
bmptexttrans=false

[logging]
logfilecount=10
loggingactive=true
loglevel=DEBUG

[katalog]
catalogfilecount=10
catalogpath=catalog
activecatalog=catalog.bin

[benennung]
**scheme**
autonaming=false
namingserverpath=C:\\netzpfad\\naming
namingservercheck=false
**useclassification**

[global]
version=Testprogramm 2.1.2.30
defaultprogversion=1.6
fotofree=true
adminmode=false
adminpasswd=testpass123
fototab=true
movietab=true
reporttab=false
rohtab=true
othertab=true
oldnew=true
createmainfolder="Foto;Movie"
checkorientation=false
wksname=MEINPC123456
wksusername=MUSTERMANN
phorem=false
molrem=false
reprem=false
rohrem=false

[transfer]
**apiserviceurl**
filenamecheck=true
photoactive=true
movieactive=true
rohactive=true
otheractive=false
reportactive=true
doubtransfer=false
nomovietransfer=true

[bildtext]
family=Arial
pointsize=48
weight=75
italic=false
imagetext=<Bildname>
fontcolor=#ffffff
bgcolor=#000000
textposition=0
vornach=true
dateiname=false
gammamemoryone=1.1
gammamemorytwo=1.3
gammamemorythree=1.5

[verteilt]
masterpath=-- Kein Master ausgew\xe4hlt --
slavepath
sharedactiv=false

[dateiparameter]
**phofiles**
**miifiles**
rohfiles=bay!cin!tif!tiff!fba!tp2!b16!mcf!
otherfiles=imh!mme!pho!mii!
repfiles=ses!inc!pc!txt!ids!
codecwhitelist=IV50.H264.X264.XVID

[tools]
toolchain

[options]
generalConf=true
loggingConf=false
catalogConf=false
fileFormatConf=true
toolConf=false
namingConf=true
shareTestConf=false
imageConf=true

Meine PowerShell-Fähigkeiten sind deutlich begrenzter.
TK1987
TK1987 15.08.2024 um 16:10:57 Uhr
Goto Top
Danke. Ich bekomme zu den zu ändernden Key-Values nicht die entsprechenden Values. Diese fehlen dann.
Kleiner Tippfehler bei einer Variable. Ist oben korrigiert.
silvereye
silvereye 15.08.2024 um 16:49:12 Uhr
Goto Top
Hallo TK1987,

jetzt funktioniert es.
Danke.