Page 1 of 1

Need help locating a line in text file and replacing it

Posted: 14 Mar 2011 23:32
by gdsimz
Hi all,

I'm needing a push in the right direct for getting substring of a variable with in a FOR and am new to DOS batch scripting. I am creating a batch file for editing an ini file and not having the luxury of using c++ or java for this need. I am trying to locate a line in a file beginning with "XYZ=..." (to later save it back) and storing the line as a variable while replacing the line with "XYZ=".

My code is as follows:

Code: Select all

@echo off
set str=teststuff
echo.%str%
set str=%str:~0,4%
echo.%str%

SETLOCAL=ENABLEDELAYEDEXPANSION

        rename c:\lotus\notes\notes.ini notes.tmp
        for /f %%a in (c:\lotus\notes\notes.tmp) do (
            set foo=%%a
       set substr=%%a:~0,11%
       echo.substr
            if substr=="KeyFileName=" set foo=""
            echo.%foo% >> c:\lotus\notes\notes.ini)


this pasted is just one of many attempts to get the substring of each to echo out for verifying a value is there.

seems that if the value to substring is static then it will return what I am expecting, but getting the substring of a variable is returning nothing " ".

I am basically intending to loop through each line and find the substring, and then replace that line (saving to put it back after batch calls an exe). I've been chasing my tail on this all day and appreciate any assistance.

Thanks for your time,

Geoff-

Re: Need help locating a line in text file and replacing it

Posted: 15 Mar 2011 17:23
by aGerman
Maybe replacing tvalues in an INI file is not safe using batch.
You have to make sure that you are in the right section. E.g.

Code: Select all

; Comment

[section1]
abc=000
xyz=123

[section2]
def=000
xyz=234

Now you want to replace the value of key xyz in section2, but not in section1...

Let's start with finding the right key:

Code: Select all

@echo off &setlocal

set "inifile=test.ini"
set "section=section2"
set "key=xyz"

for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
  for /f "tokens=1* delims==" %%b in ('more +%%a^<"%inifile%"') do (
    set "_key=%%b"
    set "value=%%c"
    setlocal enabledelayedexpansion
    if "!_key:~,1!"=="[" (endlocal&goto notFound)
    if /i "!_key!"=="%key%" (endlocal&goto found)
    endlocal
  )
)

:notFound
echo key not found
pause>nul
goto:eof

:found
echo %value%
pause>nul


Change the variables. If this will output the right value we could look forward for further actions...

Regards
aGerman

Re: Need help locating a line in text file and replacing it

Posted: 15 Mar 2011 22:14
by gdsimz
Yes,

When I change the variables, the value displays using the following:

Code: Select all

@echo off &setlocal

set "inifile=C:\lotus\notes\notes.ini"
set "section=Notes"
set "key=KeyFileName"


for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
  for /f "tokens=1* delims==" %%b in ('more +%%a^<"%inifile%"') do (
    set "_key=%%b"
    set "value=%%c"
    setlocal enabledelayedexpansion
    if "!_key:~,1!"=="[" (endlocal&goto notFound)
    if /i "!_key!"=="%key%" (endlocal&goto found)
    endlocal
  )
)

:notFound
echo key not found
pause>nul
goto:eof

:found
echo %value%

pause>nul


The 'KeyFileName' key will always be there, but value will always be different. So now having the %value%, I would like to empty the key in the existing line of text.

for example "KeyFileName=".

Doing so will allow me to perform an mst installation with out being prompted for a password (called in the bat for silent upgrade).

however I need to retain %value% so I can put it back right afterward in the same text line in the ini file.


Thanks so much for your help,

Geoff

Re: Need help locating a line in text file and replacing it

Posted: 16 Mar 2011 16:27
by aGerman
OK. I don't know whether your installation will change the INI file. For that reason we should do the same procedure twice.

Code: Select all

@echo off &setlocal

set "inifile=C:\lotus\notes\notes.ini"
set "section=Notes"
set "key=KeyFileName"

for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
  set /a n=%%a
  for /f "tokens=1* delims==" %%b in ('more +%%a^<"%inifile%"') do (
    set "_key=%%b"
    set "value=%%c"
    set /a n+=1
    setlocal enabledelayedexpansion
    if "!_key:~,1!"=="[" (endlocal&goto notFound)
    if /i "!_key!"=="%key%" (endlocal&goto found)
    endlocal
  )
)

:notFound
echo key not found
pause>nul
goto:eof

:found
echo found value %value% in line %n%

for /f "tokens=*" %%i in ("%inifile%") do (
  set "tempfile=%temp%\%%~nxi"
  set "inifile=%%~fi"
)
move /y "%inifile%" "%tempfile%"

for /f "tokens=1* delims=:" %%a in ('findstr /n "^" "%tempfile%"') do (
  set "line=%%b"
  setlocal enabledelayedexpansion
    if %%a==%n% (
      >>"%inifile%" echo(%key%=
    ) else (
      >>"%inifile%" echo(!line!
    )
  endlocal
)


:::::::::::::::::::::::::
echo do your stuff here
pause>nul
:::::::::::::::::::::::::


for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
  set /a n=%%a
  for /f "tokens=1 delims==" %%b in ('more +%%a^<"%inifile%"') do (
    set "_key=%%b"
    set /a n+=1
    setlocal enabledelayedexpansion
    if "!_key:~,1!"=="[" (endlocal&goto notFound2)
    if /i "!_key!"=="%key%" (endlocal&goto found2)
    endlocal
  )
)

:notFound2
echo key not found in 2nd step
pause>nul
goto:eof

:found2
echo found key %key% in line %n%

move /y "%inifile%" "%tempfile%"

for /f "tokens=1* delims=:" %%a in ('findstr /n "^" "%tempfile%"') do (
  set "line=%%b"
  setlocal enabledelayedexpansion
    if %%a==%n% (
      >>"%inifile%" echo(%key%=!value!
    ) else (
      >>"%inifile%" echo(!line!
    )
  endlocal
)

del "%tempfile%"


Regards
aGerman

Re: Need help locating a line in text file and replacing it

Posted: 16 Mar 2011 20:09
by ghostmachine4
Gosh, forget about batch for parsing files , even for anything!. It only has very primitive string manipulation capabilities, does not do decimal maths, has ugly syntax making maintenance and debugging difficult, slow to execute etc.
If you can't use a good programming language, use the next best thing that comes with modern Windows, vbscript (or powershell).

Code: Select all

Set objFS = CreateObject( "Scripting.FileSystemObject" )
strFile = WScript.Arguments(0)
Set objFile = objFS.OpenTextFile(strFile)
contents = objFile.ReadAll
Data = Split(contents,vbCrLf&vbCrLf)
For i=LBound(Data) To UBound(Data)
    flag = 0
   WScript.Echo "->"&Data(i)
   d = Split( Data(i) , vbCrLf )
   For j=LBound(d) To UBound(d)
      WScript.Echo "==>"&d(j)
      If InStr( d(j) , "section2" )> 0 Then
         'set flag when found section2
         flag = 1
      End If
      index = InStr( d(j), "xyz="  )
      If index > 0 And flag = 1 Then
         WScript.Echo "Found key before replacement: " & d(j)
         d(j) = Mid(d(j), 1, Len("xyz=") )
         WScript.Echo "After replacement: " & d(j)
         Exit For
      End If       
      
   Next
   Data(i) = Join(d, vbcrlf)   
Next
Data = Join(Data, vbCrLf&vbCrLf )
WScript.Echo "===================="
WScript.Echo "Final: " &Data


output

Code: Select all

C:\test>type file
; Comment

[section1]
abc=000
xyz=123

[section2]
def=000
xyz=234

C:\test>cscript //nologo test.vbs file
->; Comment
==>; Comment
->[section1]
abc=000
xyz=123
==>[section1]
==>abc=000
==>xyz=123
->[section2]
def=000
xyz=234

==>[section2]
==>def=000
==>xyz=234
Found key before replacement: xyz=234
After replacement: xyz=
====================
Final: ; Comment

[section1]
abc=000
xyz=123

[section2]
def=000
xyz=





I show the output using arrows. First of all, the script reads the whole ini file into memory. Then it splits the whole content on 2 new lines , that is, assuming your ini file has the structure as shown. The small arrow "->" shows each section being split. Next, the script splits again on 1 new line to give you the individual lines in each section. These are shown with "==>" arrows... Now, you can begin searching for your "xyz=" in "section2". When the script finds "section2" , a flag is set to 1. If "xyz=" is found and the flag is 1, that means the "xyz=" belongs to "section2" and you can do the replacement.

If you need to save to a file, use the ">" redirection

Code: Select all

cscript //nologo test.vbs file > temp
ren temp file


This method does not need to read the file multiple times ( i counted more than 8 times in the batch solution! ) using findstr , more blah blah as illustrated by aGerman's long and complicated batch file (no offense to aGerman ), hence, will be much faster than the batch solution, plus, easier to maintain and troubleshoot. If you are interested, get a copy of the vbscript manual here

Re: Need help locating a line in text file and replacing it

Posted: 17 Mar 2011 00:39
by Cleptography
This will replace all occurrences of the specified string.
Change world and planet to reflect your needs.

Code: Select all

@echo off&&setlocal

set file=%~1

for /f "tokens=*" %%- in (%file%) do (
   set str=%%-&&call :NEXT
)
goto :eof

:NEXT
set str=%str:world=planet%
echo.%str%>>New_%file%
goto :eof


Cheers-

Re: Need help locating a line in text file and replacing it

Posted: 17 Mar 2011 03:06
by ghostmachine4
Cleptography wrote:This will replace all occurrences of the specified string.
Change world and planet to reflect your needs.

Code: Select all

@echo off&&setlocal

set file=%~1

for /f "tokens=*" %%- in (%file%) do (
   set str=%%-&&call :NEXT
)
goto :eof

:NEXT
set str=%str:world=planet%
echo.%str%>>New_%file%
goto :eof


Cheers-


did you understand the question and OP's requirement that was posted ?

Re: Need help locating a line in text file and replacing it

Posted: 17 Mar 2011 10:19
by Cleptography
Oh my apologies "Ghost" I figured the obvious method was there and it was late so excuse me for not going into more detail.
Now assuming that we have an ini file that looks like so

Code: Select all

; Comment

[section1]
abc=000
xyz=123

[section2]
def=000
xyz=234


and the script we use looks like

Code: Select all

@echo off
 setlocal enabledelayedexpansion

set strR=%~1
set strW=%~2
set file=%~3

:GetStr
for /f "tokens=*" %%- in (%file%) do (
   set str=%%-&&call :ReplaceStr
)
goto :eof

:ReplaceStr
set str=!str:%strR%=%strW%!
echo.%str%
goto :eof


We can from the command line type

Code: Select all

BatchScriptName.bat "234" "456" "File.ini"


which will output

Code: Select all

[section1]
abc=000
xyz=123

[section2]
def=000
xyz=456


But wait what if we have an ini file that looks like

Code: Select all

[section1]
abc=000
xyz=123

[section2]
def=000
xyz=234

[section3]
def=000
xyz=234


Well then you add something to the above command args that specifies the section then check for it and append the number +1 to it and when that section is found it knows to change that section and no others that may include xyz=234.

Now is this wrong if so I apologize.
:shock:

Re: Need help locating a line in text file and replacing it

Posted: 22 Mar 2011 22:26
by gdsimz
Thanks you all for the replies. The file had to be created has to be a batch file for this project. aGerman's last reply does work as expected if it is clicked by the user. The process of why it has to be a batch is because the collaboration server (Lotus Domino) will update all the user workstations (for email and in house applications). There needed to be a silent install and for a silent install, the requirement was to unpack the CD install on the network, create a custom mst file, and have a batch file pushed to the user's workstation and triggered by the server.

aGerman's code works fine if the batch file is clicked by itself as it goes to the workstation ini file and performs the tasks stated above. (Thanks so much for your help aGerman btw!!)

My problem now is that when the server pushes the batch file down, the lines that trigger the query are not found so the app does not run. Not sure if it is even finding the ini file or is looking on the server (since the server is pushing it down) or if there is a permissions problem (though the workstation accounts are local admins).

Is there a way to maybe use a machine name variable ("\\"+%MACHINE%+"\"..) with a unc path the make sure it is querying the client machine?

Thanks again!

Geoff-

for reference this is what I am trying to use:

Code: Select all

@echo off &setlocal

set "inifile=C:\lotus\notes\notes.ini"
set "section=Notes"
set "key=KeyFileName"

for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
  set /a n=%%a
  for /f "tokens=1* delims==" %%b in ('more +%%a^<"%inifile%"') do (
    set "_key=%%b"
    set "value=%%c"
    set /a n+=1
    setlocal enabledelayedexpansion
    if "!_key:~,1!"=="[" (endlocal&goto notFound)
    if /i "!_key!"=="%key%" (endlocal&goto found)
    endlocal
  )
)

:notFound
echo KeyFileName for existing install not found!
echo press Enter key
pause>nul
goto:eof

:found
echo found install ini for %value% in line %n%

for /f "tokens=*" %%i in ("%inifile%") do (
  set "tempfile=%temp%\%%~nxi"
  set "inifile=%%~fi"
)
move /y "%inifile%" "%tempfile%"

for /f "tokens=1* delims=:" %%a in ('findstr /n "^" "%tempfile%"') do (
  set "line=%%b"
  setlocal enabledelayedexpansion
    if %%a==%n% (
      >>"%inifile%" echo(%key%=
    ) else (
      >>"%inifile%" echo(!line!
    )
  endlocal
)


:::::::::::::::::::::::::
echo *****
echo DO NOT CLOSE THIS WINDOW
echo *****
echo performing Lotus Notes Upgrade..

SET R85FILESPATH=\\gutil3\Tech\Apps\8upgrade\
%R85FILESPATH%setup.exe /s /v"ALLUSERS=1 TRANSFORMS=%R85FILESPATH%LotusNotes851.mst /qb+!"
%R85FILESPATH%FixPack5\setup.exe /S /v"/qb+!"
c:\lotus\notes\nconvert -d c:\lotus\notes\data\names.nsf * c:\lotus\notes\data\pernames.ntf
c:\lotus\notes\ncompact c:\lotus\notes\data -C -ZU -v -n

:::::::::::::::::::::::::


for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
  set /a n=%%a
  for /f "tokens=1 delims==" %%b in ('more +%%a^<"%inifile%"') do (
    set "_key=%%b"
    set /a n+=1
    setlocal enabledelayedexpansion
    if "!_key:~,1!"=="[" (endlocal&goto notFound2)
    if /i "!_key!"=="%key%" (endlocal&goto found2)
    endlocal
  )
)

:notFound2
echo keyFileName not found after installing updates..
echo press Enter key
pause>nul
goto:eof

:found2
echo found KeyFileName %key% in line %n%

move /y "%inifile%" "%tempfile%"

for /f "tokens=1* delims=:" %%a in ('findstr /n "^" "%tempfile%"') do (
  set "line=%%b"
  setlocal enabledelayedexpansion
    if %%a==%n% (
      >>"%inifile%" echo(%key%=!value!
    ) else (
      >>"%inifile%" echo(!line!
    )
  endlocal
)

del "%tempfile%"

Re: Need help locating a line in text file and replacing it

Posted: 25 Mar 2011 16:24
by aGerman
I'm not familiar with remote stuff. Try psexec.

Regards
aGerman