2

How can I replace a C function name with another using standard tools/scripts like: shell/awk/grep/python etc?

For example I need to blindly replace the assert(a>b) statement with MyAssert(a>b) in the entire codebase. Only function name needs to be replaced.

Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
Lunar Mushrooms
  • 8,358
  • 18
  • 66
  • 88
  • 1
    How careful do you want it to be? `printf("No assert() here\n");`? `/* assert that the world is good! */`? – Jonathan Leffler Apr 01 '14 at 04:24
  • It is okay to replace "No assert() here\n". But not okay to replace a non function text like "assert that the world is good!" . I need function name replacement, without touching non function text with same name. – Lunar Mushrooms Apr 01 '14 at 05:34
  • 1
    OK; that's reasonably sane. And presumably you want to handle `assert (space < open_parenthesis)` with one or more spaces between the function name and the open parenthesis but don't care about `assert /* Nonsense */ (paranoia != insanity);` because no-one in their right mind writes code with comments between the function name and the open parenthesis. – Jonathan Leffler Apr 01 '14 at 05:37
  • @JonathanLeffler Isn't `assert` a macro? So interposing a comment would prevent its invocation. – luser droog Apr 01 '14 at 09:22
  • @luserdroog: Comments are removed by the time macros are evaluated, so comments between macro name and its opening parenthesis don't affect the invocation of the macro. – Jonathan Leffler Apr 01 '14 at 14:05

3 Answers3

3

You can use sed

sed -r 's/\bassert\(a>b\)\b/MyAssert(a>b)/' file
  • \b looks for word boundary so that it looks for an exact match.
  • This will print the file to STDOUT which you can either redirect to another file or use -i option to make changes in-place in your existing file.
jaypal singh
  • 74,723
  • 23
  • 102
  • 147
  • 1
    I think you could simplify the code by not matching the `a>b` or the close parenthesis – that was an example. But this is good if your `sed` supports extended regular expressions with `\b`; at least, it ensures that only the word `assert` on its own gets translated, not words such as `test_assertion()`. – Jonathan Leffler Apr 01 '14 at 05:41
2
find . -iname "*.c" -exec sed -i.bak "s/assert/MyAssert/g" {} \;

This will apply the change to every .c file in place under the current directory, and create a .c.bak file containing the original. If you want to get rid of those, you could remove them with this:

find . -iname "*.bak" -exec rm {} \;

Of course, make sure you have a copy of everything first, I might have messed up :-)

If you want to catch cases more carefully, avoiding 'assert' in the middle of another word, but getting it at the beginning of a line, but it starts to get ugly, and still isn't perfect:

find . -iname "*.c" -exec sed -i.bak -e "s/\([^a-zA-Z0-9S]\)assert(/\1MyAssert(/g" -e "s/^assert(/MyAssert(/" {} \;
OldGeeksGuide
  • 2,888
  • 13
  • 23
  • I see problems with `test_assertion()` becoming `test_MyAssertion()`. – Jonathan Leffler Apr 01 '14 at 05:39
  • To fix that the regex needs to be more complicated, for example, changing it to "s/assert(/MyAssert(/g", which would catch 'assert(', so would not affect test_assertion. Ideally you'd want to check the character before the a, but then it starts to get complicated. If adding the '(' works for you, that's the easiest. – OldGeeksGuide Apr 01 '14 at 06:16
1

I wrote a Python script to solve this problem. Good things about it:

  • It doesn't modify any files that do not contain the string. Timestamps won't change unless the file actually was modified.

  • You can tweak it to only look in filenames matching a pattern (like *.c or whatever).

Replace strings in files by Python

Community
  • 1
  • 1
steveha
  • 74,789
  • 21
  • 92
  • 117