Score:1

Sed for replace a substring inside a string with a pattern

in flag

I am trying to replace a part of a pattern, such as, if I have col(3,B,14), after applying the sed command, I would like to get col(3,B,t14) which adds the t character to the third parameter in the pattern.

I am trying with :

s="col(3,B,14)"
echo $s | sed 's/col([0-9],[A-Z],[0-9])/col([0-9],[A-Z],t[0-9])/g'

But, it returns the original string. I would appreciate it if you could give some advice. Thanks.

FedKad avatar
cn flag
You should use back references in the replacement string: https://www.gnu.org/software/sed/manual/html_node/Back_002dreferences-and-Subexpressions.html
CGeorgi avatar
in flag
Thank you FedonKadifeli, yes I follow you advice and I found the solution : echo $s | sed -E 's/col(\(.*),(.*),(.*)\)/col\1,\2,t\3)/g' using the back references as you suggest. Thank very much.
Score:4
in flag

You seem a bit confused about how sed works, so I'll go step by step. My 'answer' is this:

s="col(3,B,14)"; echo $s | sed 's/\(col([0-9],[A-Z],\)/\1t/g'

Explanation

There are a couple of problems here. First, you need a semi colon after defining your variable 's', before echoing it.

s="col(3,B,14)"; echo $s 

Next, sed substitution works by 's/pattern/replacement/' - where 'pattern' is a regular expression, but where 'replacement' is not. That is, putting something like '[0-9]' in the replacement will not represent any digit, but instead represent the five characters: [, 0, -, 9, and ]. Also, the /g at the end means to keep applying the substitution on a string for every match of the pattern (so if you had a line like echo hello world | sed 's/o/z/g' then the output would be 'hellz wzrld'. Whereas echo hello world | sed 's/o/z/' would give 'hellz world')

So let's remove your replacement for now:

s="col(3,B,14)"; echo $s | sed 's/col([0-9],[A-Z],[0-9])/replacement/g'

Turning attention to the regular expression pattern you used, it says match a string like 'col(<single digit>,<uppercase letter>,<single digit>)' - notice that the last [0-9] piece won't match '14', since that is two digits and so your pattern would match say 'col(3,B,1)' but will not match 'col(3,B14)'. To match one or more digits, you can use [0-9][0-9]*:

To do the replacement as you want, the best way would be to use a 'capture group'. Capture groups 'remember' part of the match for later use. You put \( and \) around the part of the pattern you want to remember and use \1 to refer to it later:

s="col(3,B,14)"; echo $s | sed 's/\(col([0-9],[A-Z],\)/\1replacement/g'

This will match 'col(<single digit>,<uppercase letter>,' - so up to and including the point where you want to add a 't'. All of this matched stuff will be put back in the replacement (\1) followed by any text you add (in this case we're adding the literal text 'replacement'). Any remaining text not matched in the input will be unaffected. The above will output:

col(3,B,1replacement4)

So if we now put a 't' in the replacement string:

s="col(3,B,14)"; echo $s | sed 's/\(col([0-9],[A-Z],\)/\1t/g'

We get:

col(3,B,t14)

If you want to learn sed well, I can recommend an excellent tutorial.

CGeorgi avatar
in flag
Many thanks mattb for the detailed explanation. I will read the sed tutorial, for sure.
vaktare95 avatar
bf flag
The mattb answer is really great, but there's one mistake. The output after: ``` s="col(3,B,14)"; echo $s | sed 's/\(col([0-9],[A-Z],\)/\1replacement/g' ``` shoudn't be: ``` col(3,B,1replacement4) ``` but: ``` col(3,B,replacement14) ```
BeastOfCaerbannog avatar
ca flag
Instead of `[0-9][0-9]*` you could also use `[0-9]+` to match numbers with one digit or more. `+` means "match one or more of the preceding token", whereas `*` means "match zero or more of the preceding token".
mattb avatar
in flag
@vaktare95 Fixed! thank you!
Score:-2
in flag

echo $s | sed -E 's/col(\(.*),(.*),(.*)\)/col\1,\2,t\3)/g'

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.