i want to replace a unknown string between two strings.
(1(...) 2(...) 3(...))
I use:
sed -i "s/2(.*)/2(new)/g"
but i'm getting. (It take the last ')')
(1(hello) 2(new)
And i want :
(1(...) 2(new) 3(...))
Someone can help me please ?
CodePudding user response:
Try:
echo '(1(...) 2(...) 3(...))' | sed 's/2\((\.*)\)/2(new)/g'
You need to escape the brackets that you are using. to match
Update: From Benjamin W's comment
echo '(1(...) 2(TIM) 3(...))' | sed -E 's/2\([^)]*\)/2(new)/g'
CodePudding user response:
I've tried finding hack solutions for non-greedy pattern matching with sed, but have found that perl usually seems to get the job done much easier.
Unless you have a specific constraint with using only sed, you could:
echo "(1(...) 2(...) 3(...))" | perl -pe "s/2(.*?)/2(new)/g"
The only difference in the regex is the ? non-greedy modifier after the .*, which matches the first ).
The command line options are detailed here. Reference for non-greedy modifier is here.
CodePudding user response:
sed uses greedy matching so OP's attempt - 2(.*) - is going to match the 1st literal 2( plus the longest string that ends with ); consider the following where our match starts with the first 2( and runs to the last ):
$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2(.*)/2(new)/'
(1(...) 2(new) more stuff
To limit the match to the first matching ) there are a few approaches, one idea is to be explicit about what does and does not match, consider:
$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2([^)]*)/2(new)/'
(1(...) 2(new) 3(...) 2(abc) 4(...)) more stuff
In this the case we use 2([^)]*) which says to match on 2( followed by any number of characters that are not a ) ([^)]*) followed by a ).
To match on all non-greedy occurrences of 2(...) (where the ... means any non-) character) we can add the global qualifier on the end of the sed script, eg:
$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2([^)]*)/2(new)/g'
(1(...) 2(new) 3(...) 2(new) 4(...)) more stuff
