Reputation: 710
In sed
I would like to be able to match /js/
but not /js/m
I cannot do /js/[^m]
because that would match /js/
plus whatever character comes after. Negative look ahead does not work in sed
. Or I would have done /js/(?!m)
and called it a day. Is there a way to achieve this with sed that would work for most similar situations where you want a section of text that does not end in another section of text?
Is there a better tool for what I am trying to do than sed? Possibly one that allows look ahead. awk
seems a bit too much with its own language.
Upvotes: 0
Views: 713
Reputation: 203229
Well you could just do this:
$ echo 'I would like to be able to match /js/ but not /js/m' |
sed 's:@:@A:g; s:/js/m:@B:g; s:/js/:<&>:g; s:@B:/js/m:g; s:@A:@:g'
I would like to be able to match </js/> but not /js/m
You didn't say what you wanted to do with /js/ when you found it so I just put <>
around it. That will work on all UNIX systems, unlike a perl solution since perl isn't guaranteed to be available and you're not guaranteed to be allowed to install it.
The approach I use above is a common idiom in sed, awk, etc. to create strings that can't be present in the input. It doesn't matter what character you use for @
as long as it's not present in the string or regexp you're really interested in, which in the above is /js/
. s/@/@A/g
ensures that every occurrence of @
in the input is followed by A
. So now when I do s/foobar/@B/g
I have replaced every occurrence of foobar
with @B
and I KNOW that every @B
represents foobar
because all other @
s are followed by A
. So now I can do s/foo/whatever/
without tripping over foo
appearing within foobar
. Then I just unwind the initial substitutions with s/@B/foobar/g; s/@A/@/g
.
In this case though since you aren't using multi-line hold-spaces you can do it more simply with:
sed 's:/js/m:\n:g; s:/js/:<&>:g; s:\n:/js/m:g'
since there can't be newlines in a newline-separated string. The above will only work in seds that support use of \n
to represent a newline (e.g. GNU sed) but for portability to all seds it should be:
sed 's:/js/m:\
:g; s:/js/:<&>:g; s:\
:/js/m:g'
Upvotes: 3