0

In want to replace a function in a file by another. I have this :

File1.cpp:

void Component::initialize()
{
    my_component = new ComponentClass();
}

and File2.cpp:

void Component::initialize()
{
    if (doInit)
    {
        my_component = new ComponentClass();
    }
    else
    {
        my_component.ptr = null;
    }
}

I've try to write a script but my grep does not provide a result :

Old=$(grep -Eo "void Component::initialize(\n|.)*(^})*?" file1.cpp)
echo "Old=$Old" # empty variable

# My purpose is to do this :
New=$(grep -Eo "void Component::initialize(\n|.)*(^})*?" file2.cpp)
sed -i "s/$Old/$New/g" file1.cpp
A.Pissicat
  • 3,023
  • 4
  • 38
  • 93
  • needs ")" twice in bash sample and decide File* or file*? If i add 2 ")" end of line and rename files File* as file* it gives the expected output. Please test your sample before posting in here. – obayhan Jan 24 '23 at 10:35
  • 2
    A regex is not really suitable for this; to parse code properly, you need a parser. – tripleee Jan 24 '23 at 10:45
  • 3
    Use `awk` to imolement more clever things. – Matthieu Jan 24 '23 at 11:29
  • I took a look at awk but I never used it and I've no idea how to deal with my problem – A.Pissicat Jan 24 '23 at 12:27
  • 1
    @A.Pissicat Perhaps use a language that allows multi-line search instead. Ruby or Perl. – konsolebox Jan 24 '23 at 14:02
  • 1
    Please [edit] your question and add some background information. Do you have to replace the function in more than one file? Do `File1.cpp` and `File2.cpp` contain more code? If yes, then add some example code. (Otherwise `cp File2.cpp File1.cpp`) Are the functions always formatted and indented like in your example, i.e. no other curly braces in the first column, function name and arguments in a single line, opening brace of the function block in a new line below the function name? – Bodo Jan 24 '23 at 15:11
  • You could always take at look at [**this posting**](https://unix.stackexchange.com/questions/32908/how-to-insert-the-content-of-a-file-into-another-file-before-a-pattern-marker) offering sed-based approaches to a similar problem. The issue is correctly identifying the match/replace patterns. – Eric Marceau Jan 24 '23 at 19:33
  • You might want to review this [**section**](https://www.gnu.org/software/sed/manual/html_node/Multiline-techniques.html) on multi-line handling. There might be a solution there, but I am not a sed master. – Eric Marceau Jan 24 '23 at 19:56
  • Just another thought: Why not creating a subclass? – Bodo Jan 26 '23 at 10:30

3 Answers3

2
#!/usr/bin/awk -f

/^void Component::initialize\(\)$/ {
    temp = $0

    while (!/^}/ && getline > 0)
        temp = temp ORS $0

    if (NR == FNR) {
        new = temp
        nextfile
    }

    $0 = new
}

NR != FNR

Usage:

awk -f script.awk file{2,1}.cpp
konsolebox
  • 72,135
  • 12
  • 99
  • 105
0

Here is a grep-centric bash script solution (since these are what the OP mentioned explicitly):

Mac_3.2.57$cat replaceFunc.sh 
#!/bin/bash

# presumes code has been lint'd into consistent format 

oldFile=$1
newFile=$2

# find line # (oldFuncLineNum) of "void Component::initialize()" line
oldFuncLineNum=`cat $oldFile | grep -n '^void Component::initialize()$' | cut -c 1`

# find line # (oldSquiglyLineNum) of first "}" line after oldFuncLineNum
oldSquiglyLineNum=1
while [ $oldSquiglyLineNum -lt $oldFuncLineNum ]
do
  found=0
  while [ $found -eq 0 ]
  do
    oldSquiglyLineNum=`expr $oldSquiglyLineNum + 1`
    head -n $oldSquiglyLineNum $oldFile | tail -n 1 | grep '^}$' > /dev/null
    found=`test ! -f $? && echo "1" || echo "0"`
  done
done

oldTotSize=`sed -n '$=' $oldFile`
oldTailSize=`expr $oldTotSize - $oldSquiglyLineNum`

#echo "got: oldFuncLineNum = $oldFuncLineNum"
#echo "got: oldSquiglyLineNum = $oldSquiglyLineNum"
#echo "got oldTotSize = $oldTotSize"
#echo "oldTailSize = $oldTailSize"


# find line # (newFuncLineNum) of "void Component::initialize()" line
newFuncLineNum=`cat $newFile | grep -n '^void Component::initialize()$' | cut -c 1`

# find line # (newSquiglyLineNum) of first "}" line after newFuncLineNum
newSquiglyLineNum=1
while [ $newSquiglyLineNum -lt $newFuncLineNum ]
do
  found=0
  while [ $found -eq 0 ]
  do
    newSquiglyLineNum=`expr $newSquiglyLineNum + 1`
    head -n $newSquiglyLineNum $newFile | tail -n 1 | grep '^}$' > /dev/null
    found=`test ! -f $? && echo "1" || echo "0"`
  done
done

newDelta=`expr $newSquiglyLineNum - $newFuncLineNum`

#echo "got: newFuncLineNum = $newFuncLineNum"
#echo "got: newSquiglyLineNum = $newSquiglyLineNum"
#echo "got: newDelta = $newDelta"


# Display oldFile up to the function:
cat $oldFile | head -n $oldFuncLineNum

# ... followed by the new function:
cat $newFile | head -n $newSquiglyLineNum | tail -n $newDelta

# ... followed by the remaining portion of the oldFile:
cat $oldFile | tail -n $oldTailSize

exit 0
Mac_3.2.57$
Mac_3.2.57$
Mac_3.2.57$
Mac_3.2.57$cat File1.cpp 
blah blah
blah
void Component::initialize()
{
    my_component = new ComponentClass();
}
blab blab blab
...
Mac_3.2.57$
Mac_3.2.57$
Mac_3.2.57$
Mac_3.2.57$cat File2.cpp 
yaddy yadda
yaddy yadda
void Component::initialize()
{
    if (doInit)
    {
        my_component = new ComponentClass();
    }
    else
    {
        my_component.ptr = null;
    }
}
blah
blah
blab blab blab
...
Mac_3.2.57$
Mac_3.2.57$
Mac_3.2.57$
Mac_3.2.57$./replaceFunc.sh File1.cpp File2.cpp
blah blah
blah
void Component::initialize()
{
    if (doInit)
    {
        my_component = new ComponentClass();
    }
    else
    {
        my_component.ptr = null;
    }
}
blab blab blab
...
Mac_3.2.57$
Andrew
  • 1
  • 4
  • 19
  • My solution, now deleted, focused on the problem (locate/replace), not on the method (grep vs sed). That proposed solution offered what I considered a generic/simplistic/elegant approach (canned routine + mapping specification file). – Eric Marceau Feb 01 '23 at 16:03
0

Circling back with a working solution to my original non-functional answer (now deleted).

I managed to work thru the issue with the original defective script posted on linuxtopia, and was able to get the generic solution I was looking for. That is given as an answer here.

Eric Marceau
  • 1,601
  • 1
  • 8
  • 11
  • @Andrew, just want to point out that the OP selected a solution which did not involve grep, but instead used awk. As I originally commented, the specific solution that was selected was one I had thought of before it was posted, but wanted to present a more generic solution. I was happy that I was able to finally resolve the issue with the modification of a previously published (but non-functional) solution. – Eric Marceau Feb 03 '23 at 17:59