Batch to find text & insert new line of text

Microsoft Windows xp professional w/serv...
July 1, 2010 at 11:50:31
Specs: Windows XP
I need to search all the .cs files in a directory
for the word "Members", and then insert a new
line with text after it, say "Test". For example:

Current file has:
...
Members
...

After the insert:
...
Members
Test
...

I edited the solution here:
http://www.computing.net/answers/programming/batch-to-find-text-add-new-line-of-text/21255.html, to my problem below:

@echo off > newfile & setLocal enableDELAYedeXpansion

FOR /R C:\tara %%a IN (*.cs) DO (
for /f "tokens=1* delims= " %%i in (%%a) do (
>> newfile echo.%%i %%j
if "%%i" equ "Members" >> newfile echo Test
)
move /y newfile "%%a"
)

However, it does not change anything in the
file (only 1 file currently in that directory). Any tips?

Thanks!


See More: Batch to find text & insert new line of text

Report •


#1
July 1, 2010 at 17:07:01
Maybe wrap double quotes around %%a?

@echo off > newfile & setLocal enableDELAYedeXpansion
FOR /R C:\tara %%a IN (*.cs) DO (
    for /f "tokens=1* delims= " %%i in ("%%a") do (
        >> newfile echo.%%i %%j
        if "%%i" equ "Members" >> newfile echo Test
    )
    move /y newfile "%%a"
)

Insomniac at large


Report •

#2
July 1, 2010 at 20:34:39
@OrB: in order to do that, you need the funky clause "usebackq":
for /f "usebackq tokens=1* delims= " %%i in ("%%a") do (

otherwise the quoted item is interpreted as a literal and not a quoted filename. (thanks, MS, for injecting spaces into path/filenames! sarcasm index +10!!!)

@op: I don't see the problem either, so fall back to using echos and pauses etc. to debug. Most non-programmers don't understand the necessity and effectiveness of it, and it is a pain, but...
FOR /R C:\tara %%a IN (*.cs) DO (
echo current file:[%%a]
for /f "tokens=1* delims= " %%i in (%%a) do (
echo %%a, line value:[%%i][%%j]
>> newfile echo.%%i %%j
if "%%i" equ "Members" >> newfile echo Test & pause
)
move /y newfile "%%a"
)
::-----
note put NO spaces etc into the echos, you need to see exactly what the "interpreter" is seeing, hence the brackets to
offset the content. Spaces, tabs etc can wreak havoc when trying to do an exact match. Sorry i couldn't diagnose the illness, but maybe the biopsy will shed some light.



Report •

#3
July 2, 2010 at 07:02:13
Thank you for the debugging tip! By using that, I found that
"Members" was coming up in %%j instead of %%i...and I was
testing %%i to see if it was "Members".

Now for another question, how would I go about inserting multiple
lines of text after "Members"? Would I have to store the text in a
file, and somehow insert that there?

Thank you for the help!


Report •

Related Solutions

#4
July 2, 2010 at 10:07:38
If the text to be inserted is static/consistant, you can just assign it to var.s, but if it will change with circumstances, you may need a file or some dynamic type of filter to create it.
static version:
set line1=this is the first insert
set line2=this is the next line after 'members'
set line3=another added
set line4=last line to be added
::... inside main for-loop, after finding "Members", start an inner loop:
for /L %%a in (1 1 4) do >>newfile echo !line%%a!
::---- end snippet
if you need to add them from a file, do this before the main loop:
set aa=0
for /f "tokens=*" %%a in (insert.txt) do (
set /a aa+=1
set line!aa!=%%a
)
::-----

Report •

#5
July 2, 2010 at 11:52:21
That is very helpful! I am testing it out with the first snippet.

However, (for /L %%a in (1 1 4) do >>newfile echo line%%a) is
inserting the literal "line1" etc instead of the variable named
line1. How do I reference the variables I created?

Thank you!

Note: I tried putting % around that part, but it then inserts "ECHO is off." 4 times:
for /L %%g in (1 1 4) do >>newfile echo %line%%g%


Report •

#6
July 2, 2010 at 12:45:38
sorry, i fixed it in response #4... forgot the !!

Report •

#7
July 2, 2010 at 13:28:21
Ah this works great, thank you so much.

I do have one last question (hopefully): Is there a way I can
search for non-case sensitive "members" with this script?

Thanks again.


Report •

#8
July 2, 2010 at 19:20:49
if /i "%%i" equ "members" ...
add the /i switch, will ignore case. hope this helps :-)

Report •

#9
July 6, 2010 at 07:56:52
Great, thank you again!

And now that I've decided on where the inserted code is
officially going...how can I search using the regular expression
below? The problem I see is that in my script, each token is
only one "word", where I need to search for a whole string of
words (below). I guess I'm not sure how to manipulate the
"tokens delimiters" part of the for loop to end up returning
what I need into %%i or %%j or any 1 variable. Maybe I'll
have to check multiple variables? Any tips?

public.*class.*{

Current script:
set line1= test1
set line2= test2
set line3= test3
set line4= test4

for /r C:\tara %%a in (*.cs) DO (
findstr /s /i /m "<autogenerated>" %%a || (
for /f "tokens=1* delims= " %%i in (%%a) do (
>> newfile echo.%%i %%j
if /i "%%j" equ "members" (
for /L %%g in (1 1 4) do >>newfile echo !line%%g!
)
)
move /y newfile %%a
)
)

Thanks!


Report •

#10
July 6, 2010 at 10:28:40
i'm not real clear on how the "members" part fits into the r/e, but this might work for the r/e you gave:
for /f "tokens=1-3 delims=." %%b in (%%a) do (
set cc=%%c
set dd=%%d
set xx=%%b.%cc:~-5%.%dd:~-1%
if /i "%xx%" equ "public.class.{" then...
::----- end snippet
this might work as long as there are no other dots in the string. Otherwise you might send the whole string through a findstr filter:
for /f "tokens=*" %%x in ('echo %%a ^|findstr /r /i "^public\.[.]*class\.[.]*{$"') do set test=!errorlevel!
::-----
(probly would need tweaking, i'm not real confident when it comes to r/e interpretation, but that's the gist anyhow).

Report •

#11
July 6, 2010 at 11:54:27
Sorry I don't think I stated my problem very clearly heh.
Instead of inserting those 4 lines after "members", I now want
to insert it after that regular expression is found. Also, I'm not
looking for "public.class.{", the ".*" implies zero or more of
any character, so I'm looking for: "public" any chars "class"
any chars "{", and it may not all be on 1 line.

So I tried tweaking what you gave me to this:

set line1= test1
set line2= test2
set line3= test3
set line4= test4

for /r C:\tara %%a in (*.cs) DO (
findstr /s /i /m "<autogenerated>" %%a || (
for /f "tokens=*" %%x in ('echo %%a ^|findstr /r /i
public.*class.*{') do (
for /L %%g in (1 1 4) do >>newfile echo !line%%g!
)
move /y newfile %%a
)
)

However, it never makes it past searching for the reg. exp. (so
it's not finding it), and it wipes the file it searched. I think my
logic is wrong above, because I tried replacing the reg. exp.
with just a word that is found in the file, and I get the same
result. Ah sorry for so many questions


Report •

#12
July 6, 2010 at 12:20:37
it may not all be on 1 line.
This may be a problem if you plan on using FINDSTR; it only runs matches on a line.

Report •

#13
July 6, 2010 at 20:54:03
well, my feeble attempt at r/e tried to address your requirements:
"^public\.[.]*class\.[.]*{$"
(beg.of.line-"public", dot, 0-to-any no.of wildcards,"class",dot,anyno.of.wildcards,"{"-end.of.line)
(refer: findstr /?)
however, if multiple lines may possibly be inclusive of the r/e, as R2 pointed out, more persuasive artillery must be employed... vbscript prob'ly with readall and replace crlfs with nulls and then do regexp replacement.
(see recent resp R2:)

http://www.computing.net/answers/pr...


Report •

#14
July 7, 2010 at 11:29:09
Sorry my problem/goal has been evolving as this has gone on
haha. However, thanks to the above example, I have almost
completed everything! The below code does everything I want
it to...but it works by dragging-dropping a txt file into the script.

How can I change the script so that it executes on every file
within a directory, including subfolders?

I just figured it out! I went ahead and pasted my final code below for fun.

Thanks!

Set fso = CreateObject("Scripting.FileSystemObject")
Set regEx = New RegExp
Set fld = fso.GetFolder(WScript.Arguments(0))

For Each File In fld.Files

regEx.Pattern = "<autogenerated>"
regEx.Global = True

If Not(regEx.Test(fso.OpenTextFile(File).ReadAll)) Then

regEx.Pattern = "(.)*public(.)*class(.)*\n?(.)*{"
Set Matches = regEx.Execute(fso.OpenTextFile(File).ReadAll)

If Matches.Count > 0 Then
temp = split(Matches(0).Value, "public")
indent = temp(0)
s = Matches(0).Value
s = s & vbCRLF
s = s & indent & "test" & vbCRLF
s = s & indent & "test" & vbCRLF
s = s & indent & "test" & vbCRLF
s = s & indent & "test" & vbCRLF
End If

txtFile = regEx.Replace(fso.OpenTextFile(File).ReadAll, s)
fso.OpenTextFile(File, 2, True).Write txtFile

regEx.Pattern = "Log\.[a-zA-Z]{4,5}\("
Set Matches = regEx.Execute(fso.OpenTextFile(File).ReadAll)

For Each Match in Matches
temp = split(Match.Value,".")
middle = split(temp(1), "(")
s = "Log." & middle(0) & "Format("

txtFile = regEx.Replace(fso.OpenTextFile(File).ReadAll, s)
fso.OpenTextFile(File, 2, True).Write txtFile
Next

End If
Next


Report •

#15
July 7, 2010 at 15:09:04
Alas...I'm not done. I realized the code posted above does
not search subfolders. I tried the SubFolders member of the
Folder object, but it is not recursive and does not include the
files in the root folder.

I can do it from a batch file that first calls the script with the
root folder, then uses "for /D..." to get all subfolders. However,
I would like to only have one file (vbs) rather than the vbs and
bat.

Is there any semi-simple way to accomplish this with my
code? All of the vbscript I've found for recursive subfolders was
way over my head so far. I've posted my most recent code
below:

Set outFSO = CreateObject("Scripting.FileSystemObject")
Set outFile =
outFSO.OpenTextFile("C:\tara\changelog.txt",8,True)

outPath =
outFSO.GetAbsolutePathName("C:\tara\changelog.txt")
outName = outFSO.GetFileName(outPath)

Set fso = CreateObject("Scripting.FileSystemObject")
Set regEx = New RegExp
Set fld = fso.GetFolder(WScript.Arguments(0))

For Each File in fld.Files
If (StrComp(File.Type,"Visual C# Source file",1) = 0) Then

regEx.Pattern = "<autogenerated>"
regEx.Global = True
If Not(regEx.Test(fso.OpenTextFile(File).ReadAll)) Then

Change

End If
End If
Next

Sub Change
mylog = ""

regEx.Pattern = "(.)*public(.)*class(.)*\n?(.)*{"
Set Matches =
regEx.Execute(fso.OpenTextFile(File).ReadAll)

If Matches.Count > 0 Then
mylog = mylog & vbTab & "***** INSERT *****" & vbCRLF
mylog = mylog & vbTab & "old: " & vbCRLF & vbTab &
Matches(0).Value & vbCRLF
temp = split(Matches(0).Value, "public")
indent = temp(0)
s = Matches(0).Value
s = s & vbCRLF
s = s & indent & vbTab & "test" & vbCRLF
s = s & indent & vbTab & "test" & vbCRLF
s = s & indent & vbTab & "test" & vbCRLF
s = s & indent & vbTab & "test" & vbCRLF
mylog = mylog & vbTab & "new: " & vbCRLF & vbTab & s &
vbCRLF
txtFile = regEx.Replace(fso.OpenTextFile(File).ReadAll, s)
fso.OpenTextFile(File, 2, True).Write txtFile
End If

regEx.Pattern = "(.)*Log\.[a-zA-Z]{4,5}\((.)*"
Set Matches =
regEx.Execute(fso.OpenTextFile(File).ReadAll)

If Matches.Count > 0 Then
mylog = mylog & vbTab & "***** REPLACE *****" & vbCRLF
temp = split(Matches(0).Value, "public")
indent = temp(0)
For Each Match in Matches
mylog = mylog & vbTab & "old: " & Match.Value & vbCRLF
temp = split(Match.Value,".")
middle = split(temp(1), "(")
s = indent & "Log." & middle(0) & "Format("
mylog = mylog & vbTab & "new: " & s & vbCRLF
txtFile = regEx.Replace(fso.OpenTextFile(File).ReadAll, s)
fso.OpenTextFile(File, 2, True).Write txtFile
Next
End If

If (StrComp(mylog,"") <> 0) Then
outFile.WriteLine("file: " & File.Name & vbCRLF & mylog)
End If

End Sub


Report •

#16
July 12, 2010 at 09:04:53
Any ideas?

Report •

#17
July 12, 2010 at 11:44:14
try this (snipped out of your script above & modified):

Set fld = fso.GetFolder(WScript.Arguments(0))
test
wscript.quit

sub test
wscript.stdout.writeline("folder: "&fld.name)
For Each File in fld.Files
If (StrComp(File.Type,"Visual C# Source file",1) = 0) Then
regEx.Pattern = "<autogenerated>"
regEx.Global = True
If Not(regEx.Test(fso.OpenTextFile(File).ReadAll)) Then
wscript.stdout.writeline("C# source: "&file.name)
Change
End If
Next
for each subfolder in fld.subfolders
set fld=fso.getfolder(subfolder.path)
test
next
end sub


Report •


Ask Question