Regular expression in sed to replace C++ includes - c++

I'm trying to play with sed, to change all;
#include "X"
to:
#include <X>
However I can't seem to find a way to do this! - This is what I've done so far:
sed -i 's/#include ".*"/#include <.*>/g' filename
I think I'm in need of a variable to save the contains of ".*", i'm just unaware of how!

Yes, you do. Regexps use () to save the contents of a match and a \1 to retrieve it. If you use more than one set of (), then the 2nd match is in \2 , and so on.
sed -e 's/#include "\(.*\)"/#include <\1>/g' < filename
will do what you need.

Try:
sed 's/#include "\(.*\)"/#include <\1>/' x.cpp

Try:
sed -i 's/#include "\(.*\)"/#include <\1>/g' filename

Related

Replace a > with a " sed regular expression

I have lots of files that have lines that are in the following way:
#include "3rd-party/*lots folders*>
problem is that it ends with > instead of "
Is there a quick regex for sed to change that?
basically, if the line starts with #include "3rd-party, it should replace the last character to ".
Thanks in advance
You can use this:
sed -i '' '/^[[:blank:]]*#include "3rd-party/s/>$/"/' file
#include "3rd-party/*lots folders*"
Basically you can use:
sed '/^[[:space:]]*#include "3rd-party/s/>[[:space:]]*$/"/' file
Explanation:
/^[[:space:]]*#include/ is an address, a regular expression address. The subsequent command will apply to lines which start which optional space followed by an #include statement.
s/>[[:space:]]*$/"/ replaces > followed by optional space and the end of the line by a ".
Use the -i option if you want to change the file in place:
sed -i '/^[[:space:]]*#include/s/>[[:space:]]*$/"/' file
On a bunch of, let's say C files, use find and it's -exec option:
find . -name '*.c' -exec sed -i '/^[[:space:]]*#include/s/[[:space:]]*$/"/' {} \;
You can use sed for searching a pattern and doing an action on this line like
sed '/search_pattern/{action}' your_file
The action you want to do is replacing the last character in a line with >$ where > is your desired character and $ means that the searched character must be placed at the end of a line.
The action for doing this is the sedcommand s/// which work's like s/search_pattern/replace_pattern/.
This looks for your goal like:
sed '/#include "3rd-party/{s/>$/"/}' your_file
But since sed is a (s)tream (ed)itor you have to use sed's command flag -i to make your changes inline or pipe it with > to a new file.
Like this
sed -i '/#include "3rd-party/{s/>$/"/}' your_file
or like this
sed '/#include "3rd-party/{s/>$/"/}' your_file > new_file
Please let me know if this does your work.

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.
N.B. 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;
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.
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
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 /, \, &, ...

sed - Commenting a line matching a specific string AND that is not already commented out

I have the following test file
AAA
BBB
CCC
Using the following sed I can comment out the BBB line.
# sed -e '/BBB/s/^/#/g' -i file
I'd like to only comment out the line if it does not already has a # at the begining.
# sed -e '/^#/! /BBB/s/^/#/g' file
sed: -e expression #1, char 7: unknown command: `/'
Any ideas how I can achieve this?
Assuming you don't have any lines with multiple #s this would work:
sed -e '/BBB/ s/^#*/#/' -i file
Note: you don't need /g since you are doing at most one substitution per line.
Another solution with the & special character which references the whole matched portion of the pattern space. It's a bit simpler/cleaner than capturing and referencing a regexp group.
sed -i 's/^[^#]*BBB/#&/' file
I find this solution to work the best.
sed -i '/^[^#]/ s/\(^.*BBB.*$\)/#\ \1/' file
It doesn't matter how many "#" symbols there are, it will never add another one. If the pattern you're searching for does not include a "#" it will add it to the beginning of the line, and it will also add a trailing space.
If you don't want a trailing space
sed -i '/^[^#]/ s/\(^.*BBB.*$\)/#\1/' file
Assuming the BBB is at the beginning of a line, I ended up using an even simpler expression:
sed -e '/^BBB/s/^/#/' -i file
One more note for the future me. Do not overlook the -i. Because this won't work: sed -e "..." same_file > same_file.
sed -i '/![^#]/ s/\(^.*BBB.*$\)/#\ \1/' file
This doesn't work for me with the keyword *.sudo, no comments at all...
Ony the syntax below works:
sed -e '/sudo/ s/^#*/#/' file
Actually, you don't need the exclamation sign (!) as the caret symbol already negates whatever is inside the square brackets and will ignore all hash symbol from your search. This example worked for me:
sed -i '/[^#]/ s/\(^.*BBB.*$\)/#\ \1/' file
Comment all "BBB", if it's haven't comment yet.
sed -i '/BBB/s/^#\?/#/' file
If BBB is at the beginning of the line:
sed 's/^BBB/#&/' -i file
If BBB is in the middle of the line:
sed 's/^[^#]*BBB/#&/' -i file
I'd usually supply sed with -i.bak to backup the file prior to making changes to the original copy:
sed -i.bak '/BBB/ s/^#*/#/' file
This way when done, I have both file and file.bak and I can decide to delete file.bak only after I'm confident.
If you want to comment out not only exact matches for 'BBB' but also lines that have 'BBB' somewhere in the middle, you can go with following solution:
sed -E '/^([^#].*)?BBB/ s/^/#/'
This won't change any strings that are already commented out.

Perl regexp replace?

I'm checking to see if I can replace an include like this:
#include <pathFoo/whatever.H>
with:
#include "whatever.H"
to do so I would use the -i switch, but to check I am doing it correctly I am simply using the -p switch without -i. I have the following command:
perl -p -e 's/<pathFoo\/\(.*\)>/"$1"' thefile
but this isn't quite working and i'm not exactly sure which part is off?
You don't want to escape the parens, i.e.:
perl -p -e 's/<pathFoo\/(.*)>/"$1"/' thefile
should work for you.
Also note the ending /.
perl -i~ -pe's!<pathFoo/(.*)>!"$1"!' file
The following is safer:
perl -i~ -pe's!#include\s+\K<pathFoo/(.*)>!"$1"!' file
Since TIMTOWTDI, here's a double substitution. Or rather a substitution and a transliteration:
perl -pe 's|^#include\s+<\KpathFoo/|| && tr/<>/""/'
So, just remove the pathFoo/ part first, and if that succeeds, then transliterate the <> characters to quotes.
I think this will get you there:
perl -pi -e 's{#include[ ]+<.+?/([^/]+)>}{#include "$1"}g' file

How to use regular expression in sed command

i have some strings with this pattern in some files:
domain.com/page-10
domain.com/page-15
....
and i want to replace them with something like
domain.com/apple-10.html
domain.com/apple-15.html
i have found that i can use sed command to replace them at a time but because after the numbers should something be added i guess i have to use regular expression to do it. but i don't know how.
sed -i.bak -r 's/page-([0-9]+)/apple-\1.html/' file
sed 's/page-\([0-9][0-9]*\)/apple-\1.html/' file > t && mv t file
Besides sed, you can also use gawk's gensub()
awk '{b=gensub(/page-([0-9]+)/,"apple-\\1.html","g",$0) ;print b }' file
sed -i 's/page-\([0-9]*\)/apple-\1.html/' <filename>
The ([0-9]*) captures a group of digits; the \1 in the replacement string references that capture and adds it as part of the replacement string.
You may want to use something like -i.backup if you need to keep a copy of the file without the replacements, or just omit the -i and instead use the I/O redirection method instead.
One more way to resolve the problem:
sed -i.bak 's/\(^.*\)\(page-\)\(.*\)/\1apple-\3.html/' Files
Here the searching patterns are stored and retrieved using references (\1, \2, \3).
This will work
sed 's/$/\.html/g' file.txt