sed: Replace lines matching a pattern that contains forward slashes? - regex

I know this question has been asked before, I just can't seem to get the correct syntax for my sed command.
I need to replace OPP/com.user.opp.orchest.po.services.stub-npo/npo-stub with OPP/com.user.opp.orchest.po.services.stub-ica/npo-ica
A snippet of the file I am replacing it is the following:
config.xml
<compareType>PLAIN</compareType>
<pattern>
OPP/com.user.opp.orchest.po.services.stub-npo/npo-stub
</pattern>
<branches>
<com.sonyuser.hudson.plugins.gerrit.trigger.hudsontrigger.data.Branch>
<compareType>ANT</compareType>
<pattern>master</pattern>
</com.sonyuser.hudson.plugins.gerrit.trigger.hudsontrigger.data.Branch>
</branches>
${REPO_MIRROR}/OPP/com.user.opp.orchest.po.services.stub-npo/npo-stub
I have tried the following,
sed -i '/^\/OPP/\com.user.opp.orchest.po.services.stub-npo/\npo-stub\/OPP/\com.user.opp.orchest.po.services.stub-ica/\npo-ica/g' config.xml

In your command, you are missing s for substitution and have wrongly escaped \ character. Also as you replied to my comment, that you want to replace it from anywhere in the file, you don't have to use ^ character in your regex. And dot . in regex means any character so they need to be escaped too.
You can use this command,
sed -i 's/OPP\/com\.user\.opp\.orchest\.po\.services\.stub-npo\/npo-stub/OPP\/com.user.opp.orchest.po.services.stub-ica\/npo-ica/g' yourfilename

You need to specify s command and replace the /\ with \/. There are some other typos here as well (\/ at the start is not necessary). Also, escape dots to match literal dots. A good idea is to use some other delimiter here instead of /, e.g. ,, because you have / chars in the regex and replacement parts.
You may use
sed -i 's,^OPP/com\.user\.opp\.orchest\.po\.services\.stub-npo/npo-stub,OPP/com.user.opp.orchest.po.services.stub-ica/npo-ica,' file
See the online demo

Related

Regex to match a path, excluding the final directory. Perl error "search pattern not terminated at -e"

Say I have a directory path
/abc/de/fgh/i/jk
And I just want to match
/abc/de/fgh/i/
How would I do this? I have tried:
(\/.*\/)*
In https://regexr.com/ and it seems to do the trick.
However, when I try:
path="/abc/de/fgh/i/jk"
sliced=`echo $path | perl -pe '(\/.*\/)*'`
I get the error:
Search pattern not terminated at -e line 1
Is there a better way to do this besides perl? What is wrong here anyway to give a perl error? Is my regex even correct here?
There is a coreutil to do this, dirname:
path="/abc/de/fgh/i/jk"
sliced=`dirname "$path"`
However, it also removes the trailing /. If you, for whatever reason, need it, just append it to sliced:
sliced=`dirname "$path"`/
Be sure to quote $path; it won't work with paths with spaces in them if you don't.
Your Perl program isn't working because you haven't put any regex operators around it. It ignores the first \ since it isn't in a string or regex, then finds the /, which begins a regex. Since there's no unescaped / to end it, it gives you that error. You probably want something like s/(\/.*\/)*.*/$1/, which should erase everything after the last /.
Use sed, but match what you want to remove (rather than what you want to keep):
echo $path | sed 's,[^/]*$,,'
Outputs /abc/de/fgh/i/
The regex matches all non-slash chars at the end and replaces them with nothing, removing them.
Why not use Parameter Expansion ?
echo "${path%/*}/"

I need to use sed to comment out two lines in a text file

I am running a custom kernel build and have created a custom config file in a bash script, now I need to comment out two lines in Kbuild in order to prevent the bc compiler from running. The lines are...
$(obj)/$(timeconst-file): kernel/time/timeconst.bc FORCE
$(call filechk,gentimeconst)
Using Expresso, I have a regex that matches the first line...
^\$\(obj\)\/\$\(timeconst-file\): kernel\/time\/timeconst\.bc FORCE
Regex Match
But can't get sed to actually insert a # in front of the line.
Any help would be much appreciated.
sed -i "/<Something that matches the lines to be replaced>/s/^#*/#/g"
This uses a regex to select lines you want to comment/<something>/, then substitutes /s/ the start of the string ^(plus any #*s already there, with #. So you can comment lines that are already commented no problem. the /g means continue after you found your first match, so you can do mass commenting.
I have a bash script that I can mass comment using the above as:
sed -i.bkp "/$1/s/^#\+\s*//g" $2
i.bkp makes a backup of the file named .bkp
Script is called ./comment.sh <match> <filename>
The match does not have to match the entire line, just enough to make it only hit lines you want.
You can use following sed for replacement:
sed 's,^\($(obj)/$(timeconst-file): kernel/time/timeconst.bc FORCE\),#\1,'
You don't need to escape ( ) or $, as in sed without -r it is treated as literal, for grouping \( \) is used.

White spaces in sed search string

I want to substitute a String from a file which is:
# - "server1"
My first attempt was something like this:
sed -i 's/#\ -\ "\server1"\.*/ChangedWord/g' file
But I get an error if I try it like this.
So there is to be another way to handle whitespaces, I guess I have to use \s or [[:space:]]. But for some how I am not able to make it work.
I think you are complicating the expression too much. This should be enough:
sed 's/^#[[:space:]]*-[[:space:]]*"server1".*/ChangedWord/' file
It looks for those lines starting with # followed by 0 to n spaces, then "server1" and then anything. In such case, it replaces the line with ChangedWord.
Note I am using [[:space:]] to match the spaces, since it is a more compatible way (thanks Tom Fenech in comments).
Note also there is no need to use g in the sed expression, because the pattern can occur just once per line.
Test
$ cat a
hello
# - "server1"
hello# - "server1"
$ sed 's/^#[[:space:]]*-[[:space:]]*"server1".*/ChangedWord/' a
hello
ChangedWord
hello# - "server1"
The actual fault was the missing escaping from the double quotes:
ssh -i file root#IP sed 's/^#[[:space:]]*-[[:space:]]*\"server1\".*/ChangedWord/' file
That did it for me. Thanks for all your support
rghome is right, you don't need those backslashes in front of spaces as the expression is wrapped in quotes. In fact, they're causing the error: sed is telling you that \<Space> is not a valid option. Just remove them and it should work as expected:
sed -i 's/# - "server1"/ChangedWord/' file

Add curly braces to string after a match (sed)

I'm a beginner with regexes and I'm trying to achieve something relatively simple:
I have a dataset arranged like this:
1,AAA,aaaa,BBB,bbbbbb ...
2,AAA,aaaaaaa,BBB,bbb ...
3,AAA,aaaaa,BBB,bb ...
I'm looking into adding curly brackets to the strings of various length (alphanumeric chars) following AAA or BBB (these are constant):
1,AAA,{aaaa},BBB,{bbbbbb} ...
2,AAA,{aaaaaaa},BBB,{bbb} ...
3,AAA,{aaaaa},BBB,{bb} ...
So I have tried with sed this way:
sed 's/(AAA|BBB)[[:punct:]].[[:alnum:]]/\1{&}/g' dataset.txt
However I got this result:
1,AAA,{AAA,aa}aa,BBB,{BBB,bb}bbbb, ...
2,AAA,{AAA,aa}aaaaa,BBB,[BBB,bb}b, ...
3,AAA,{AAA,aa}aaa,BBB,{BBB,bb} ...
Obvisouly, the & in the replace part of sed is going to be the matched pattern, however, I would like & to be only what is after the matched patter, what am I doing wrong?
I have also tried adding word boundaries, after [^ ] to no avail. Am I trying too hard with sed? Should I use a language that allows lookbehind instead?
Thanks for any help!
Try this:
sed 's/\(AAA\|BBB\),\([^,]*\)/\1,{\2}/g' dataset.txt
You can always have more than 1 capture groups in your regex, to capture different parts. You can even move the [:punct:] part inside the first capture group:
sed 's/((?:AAA|BBB)[[:punct:]])([[:alnum:]]+)/\1{\3}/g' dataset.txt
I don't understand what that . in between [:punct:] and [:alnum:] was doing. So, I removed it. Because of that, you might have noticed that, the regex was matching the following pattern:
{AAA,aa}
{BBB,bb}
i.e, it was matching just 2 characters after AAA and BBB. One for . and one for [[:alnum:]].
To match all the alphanumeric characters after , till the next , you need to use quantifier: [[:alnum:]]+
Following sed should work.
On Linux:
sed -i.bak -r 's/((AAA|BBB)[[:punct:]])([[:alnum:]]+)/\1{\3}/g'
OR on OSX:
sed -i.bak -E 's/((AAA|BBB)[[:punct:]])([[:alnum:]]+)/\1{\3}/g'
-i is for inline option to save changes in the input file itself.

using sed to copy lines and delete characters from the duplicates

I have a file that looks like this:
#"Afghanistan.png",
#"Albania.png",
#"Algeria.png",
#"American_Samoa.png",
I want it to look like this
#"Afghanistan.png",
#"Afghanistan",
#"Albania.png",
#"Albania",
#"Algeria.png",
#"Algeria",
#"American_Samoa.png",
#"American_Samoa",
I thought I could use sed to do this but I can't figure out how to store something in a buffer and then modify it.
Am I even using the right tool?
Thanks
You don't have to get tricky with regular expressions and replacement strings: use sed's p command to print the line intact, then modify the line and let it print implicitly
sed 'p; s/\.png//'
Glenn jackman's response is OK, but it also doubles the rows which do not match the expression.
This one, instead, doubles only the rows which matched the expression:
sed -n 'p; s/\.png//p'
Here, -n stands for "print nothing unless explicitely printed", and the p in s/\.png//p forces the print if substitution was done, but does not force it otherwise
That is pretty easy to do with sed and you not even need to use the hold space (the sed auxiliary buffer). Given the input file below:
$ cat input
#"Afghanistan.png",
#"Albania.png",
#"Algeria.png",
#"American_Samoa.png",
you should use this command:
sed 's/#"\([^.]*\)\.png",/&\
#"\1",/' input
The result:
$ sed 's/#"\([^.]*\)\.png",/&\
#"\1",/' input
#"Afghanistan.png",
#"Afghanistan",
#"Albania.png",
#"Albania",
#"Algeria.png",
#"Algeria",
#"American_Samoa.png",
#"American_Samoa",
This commands is just a replacement command (s///). It matches anything starting with #" followed by non-period chars ([^.]*) and then by .png",. Also, it matches all non-period chars before .png", using the group brackets \( and \), so we can get what was matched by this group. So, this is the to-be-replaced regular expression:
#"\([^.]*\)\.png",
So follows the replacement part of the command. The & command just inserts everything that was matched by #"\([^.]*\)\.png", in the changed content. If it was the only element of the replacement part, nothing would be changed in the output. However, following the & there is a newline character - represented by the backslash \ followed by an actual newline - and in the new line we add the #" string followed by the content of the first group (\1) and then the string ",.
This is just a brief explanation of the command. Hope this helps. Also, note that you can use the \n string to represent newlines in some versions of sed (such as GNU sed). It would render a more concise and readable command:
sed 's/#"\([^.]*\)\.png",/&\n#"\1",/' input
I prefer this over Carles Sala and Glenn Jackman's:
sed '/.png/p;s/.png//'
Could just say it's personal preference.
or one can combine both versions and apply the duplication only on lines matching the required pattern
sed -e '/^#".*\.png",/{p;s/\.png//;}' input