0

I am trying to read content of a file, after finding matching with content need to skip one more line & add some text.

For Ex: My text file contains:

cd $home/t17_0/download/functional-tests/
ant compile-all
cd $home/15_5/download/functional-tests/
ant compile-all
cd $home/15_7/download/functional-tests/
ant compile-all

I want match line with cd $home/15_5/download/functional-tests/ (line number 3) and add cd $home/15_6/download/functional-tests/ after ant compile-all (line number 4). Please note that in my real scenario i don't know the line number.

I am able to write script to add the text after matching the content as shown below:

$mat='cd $home/15_5/download/functional-tests/'
$add='cd $home/15_6/download/functional-tests/'
$file_content=get-content text.txt
($file_content) | foreach-object {
    $_ 
    if ($_ -contains $mat) 
    {
        $add
    }
}| set-content $file_content

This is matching line with cd $home/15_5/download/functional-tests/ (line number 3) and adds cd $home/15_6/download/functional-tests/ before ant compile-all (line number 4).

Matt
  • 45,022
  • 8
  • 78
  • 119
peer
  • 3
  • 3
  • sorry,i had copied only that particular line from script, now i have updated the ques. @AnsgarWiechers: Yes, thats my question, i want to insert a line 2 lines after the matching line. I have scripted as below for now, but am looking for better solution.$ant='ant compile-all' $file_content=get-content text.txt ($file_content) | foreach-object {$_ if ($_ -contains $mat){$ant$add}}| set-content $file_content which gave me output as expected by adding those 2 lines after line 3: but am looking for better solution, i don't want to declare & add 'ant compile-all' in my script. Thanks – peer May 25 '15 at 16:41

2 Answers2

2

There are several ways you could go about this. For instance you could use a regular expression:

$file = 'C:\path\to\your.txt'

$mat  = 'cd $home/15_5/download/functional-tests/'
$add  = 'cd $home/15_6/download/functional-tests/'

$pattern = "(?m)(" + [regex]::escape($mat) + "`r`nant compile all)"

(Get-Content $file -Raw) -replace $pattern, "`$1`r`n$add" |
  Set-Content $file

or a StreamReader:

$file = 'C:\path\to\your.txt'

$mat  = 'cd $home/15_5/download/functional-tests/'
$add  = 'cd $home/15_6/download/functional-tests/'

$reader = [IO.File]::OpenText($file)

$text = while ($reader.Peek() -ge 0) {
          $line = $reader.ReadLine()
          $line
          if ($line -eq $mat) {
            $reader.ReadLine()
            $add
          }
        }
$reader.Close()

$text | ? { $_ } | Set-Content $file

The ? { $_ } filter above is a safeguard to prevent the file from being truncated in case $text is empty.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
0

When you use Get-Content every line has a Readcount we can use that to find the line that matches your text and then output the lines back to file. Also we need to escape the text $toMatch since it contains regex control characters ($).

$toMatch = [regex]::Escape('cd $home/15_5/download/functional-tests/')
$toAdd = 'cd $home/15_6/download/functional-tests/'
$fileData = Get-Content $pathtofile
$matchedLineNumber = $fileData | Where-Object{$_ -match $toMatch} | Select-Object -Expand ReadCount

$fileData | ForEach-Object{
    $_
    If($_.ReadCount -eq ($matchedLineNumber + 1)){
        $toAdd
    }
} | Set-Content $pathtofile

If the file is large then using something like in Ansgar's Answer would be more efficient. $matchedLineNumber contains the line number where we find the text. Then while inside the loop we look for the next line (where the +1 is used). After finding that match we output the extra text $toAdd.

-Contains

It is one of the gotchas of PowerShell. Have a look at this answer to understand how that is supposed to be used.

Community
  • 1
  • 1
Matt
  • 45,022
  • 8
  • 78
  • 119