0

I need help to replace the below 2 lines of code in a Python file with sed. We are loading one Python file which processes some data, so we need to replace the below 2 lines of code with another line without affecting indentation.

I have tried sed command many, and all work for normal text lines, but none of them works for lines which has space/tabs ^[ \s] or ^[ \t]

def get_user_creds(user):
    # some lines of code
    user.invoke()
    user.process(user)

expected :

def get_user_creds(user):
    # some lines of code
    user.reinvoke()
7
  • Hey, can you try this command? "sed -E -i "s/^\s+user\.invoke()/\tuser.reinvoke()/g; s/^\s+user\.process(user)/\tuser.process_userdata(user)/g" your_file.py" Commented May 31, 2023 at 9:32
  • Do you need to do this more than once? Why would you not just use an editor to fix it and save a new version of the file, rather than use an editor to write a ten-line script to patch the code, and then test it. Commented May 31, 2023 at 9:35
  • @WinnieTigger (a) there may be other occurrences of both those calls -- we should probably restrict the fix to be only inside the function get_user_creds. (b) what is the purpose of the g global modifier in sed ? Commented May 31, 2023 at 9:39
  • @WinnieTigger sorry problem here is need to replace both methods with one single method
    – Abhi Ram
    Commented May 31, 2023 at 9:47
  • @Paul_Pedant this is needed as this file will be pickedup automatically and builds an image so its not possible to edit the file manully it should be run as command to replace
    – Abhi Ram
    Commented May 31, 2023 at 9:49

2 Answers 2

1

It would be very easy to insert re in all lines with user.invoke() and delete all with user.process(user), so I guess the problem is to change these lines only if they appear together.

In sed, when you always need to process two lines together, you use the N;P;D pattern, always appending the Next line, doing you stuff with both lines, then Print and Delete the first line to continue with the next one.

In your case:

sed '$!N;s/user.invoke().*\n.*user.process(user)/user.reinvoke()/;P;D'

(Currently, I can't test that, but I'm confident that it will work.)

1
  • Thanks @Philippos it worked for me and I'm I see no other lines were modified and Thanks a lot
    – Abhi Ram
    Commented Jun 5, 2023 at 14:37
0

Using Raku (formerly known as Perl_6)

~$ raku -e 'put slurp.subst(:global, / \h+ <( "user.invoke()" \n \h+ "user.process(user)" )> /, "user.reinvoke()" );'  file

Sample Input:

def get_user_creds(user):
    # some lines of code
    user.invoke()
    user.process(user)

Sample Output:

def get_user_creds(user):
    # some lines of code
    user.reinvoke()

Raku is a programming language in the Perl family. Above the file is slurped in (i.e. read into memory all at once), then a substitution is performed with the :global parameter (adverb), meaning every two-line match in the file will be replaced.

The matcher / \h+ <( "user.invoke()" \n \h+ "user.process(user)" )> / looks for the two literal strings (in double quotes), surrounded by the appropriate whitespace (\h for horizontal whitespace, \n for newline). Once matched, the <()> capture markers are used to delineate what is to be replaced. Here, the initial \h+ is not within the capture markers, and thus is retained in the output, adjacent to the newly inserted string (i.e. "respecting indentation").

Generally, escaping Regexes is a pain. However Raku simplifies the process by allowing literal strings (above, in double-quotes). If quotes are a problem, then backslashes work: simply backslash all non-[alnum or underscore] to have those characters understood literally. This reserves non-backslashed non-[alnum or underscore] characters (in the same category as "." dot) to take on special meaning in the future, even if no special meaning is conferred at the moment.

FYI, you can get very specific with captures/replacements. Below the strings "user." and "invoke()" are captured, and in the replacement "re" is interposed to make "reinvoke()":

~$ raku -e 'put S:g/ \h+ <( ("user.") ("invoke()") \n \h+ "user.process(user)" )> /$0re$1/ given slurp();'  file

#OR

~$ raku -e 'put S:g[ \h+ <( ("user.") ("invoke()") \n \h+ "user.process(user)" )> ] = "$0re$1" given slurp();'  file

https://docs.raku.org/language/regexes
https://raku.org

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .