简体   繁体   中英

Selective find/replace with sed

I need to do some find and replace in C++ source code: replace all occurrences of _uvw with xyz except when _uvw is part of abc_uvw or def_uvw . For example:

abc_uvw ghi_uvw;
jkl_uvw def_uvw;

should become:

abc_uvw ghixyz;
jklxyz def_uvw;

So far I came up with the following:

find . -type f -print0 | xargs -0 sed -i '/abc_uvw/\!s/_uvw/xyz/g'

This will replace all _uvw with xyz only in the lines that don't contain abc_uvw , which (1) doesn't handle such a case: abc_uvw ghi_uvw; and (2) doesn't take into account the second exception, that is def_uvw .

So how would one do that sort of selective find and replace with sed?

This might work for you (GNU sed):

sed -r 's/(abc|def)_uvw/\1\n_uvw/g;s/([^\n])_uvw/\1xyz/g;s/\n//g' file

Insert a newline infront of the strings you do not want to change. Change those strings which do not have a newline infront of them. Delete any newlines.

NB Newline is chosen as it cannot exist in an unadulterated sed buffer.

How about this?

$ cat file
abc_uvw ghi_uvw;
jkl_uvw def_uvw;

$ sed 's/abc_uvw/foo/g;s/def_uvw/bar/g;s/_uvw/xyz/g;s/foo/abc_uvw/g;s/bar/def_uvw/g' file
abc_uvw ghixyz;
jklxyz def_uvw;

This will work:

sed -e 's/abc_uvw/AAA_AAA/g;        # shadow abc_uvw
        s/def_uvw/DDD_DDD/g;        # shadow def_uvw
        s/_uvw/xyz/g;               # substitute
        s/AAA_AAA/abc_uvw/g;        # recover abc_uvw
        s/DDD_DDD/def_uvw/g         # recover def_uvw
        ' input.cpp > output.cpp

cat output.cpp

You should use negative lookbehind. For example, in Perl:

perl -pe 's/(?<!(abc|def))_uvw/xyz/g' file.c

This performs a global substitution of any instances of _uvw that are not immediately preceded by abc or def .

Output:

abc_uvw ghixyz;
jklxyz def_uvw;

Sed is a useful tool and certainly has its place but Perl is a lot more powerful in terms of regular expressions. Using Perl, you get to specify exactly what you mean, rather than solving the problem in a more roundabout way.

sed 's/µ/µm/g;s/abc_uvw/µa/g;s/def_uvw/µd/g
     s/_uvw/xyz/g
     s/µd/def_uvw/g;s/µa/abc_uvw/g;s/µm/µ/g' YourFile

This is like the other in concept but "escaping" first the temporary pattern to filter on abc and def. I use µ but other char is possible, just avoid special sed char like / , \\ , & , ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM