AimThe aim is to convert the following string:hello_hello,123-world567-helloworld123456,world1234-hello09876using sed into a specific format.Attemptssed -e 's|^\(hello_[a-z0-9]\{3\}\)\(.*\)|\1,\1\2|g;s|..|&/|g' /tmp/fileExpected outcomehe/ll/o_/he/ll/o,123-world567-helloworld123456,/wo/rl/d1/23/4-/he/ll/o0/98/76/Current outcomeThe problem is that every 2 characters a / is inserted. The insertion of / should be avoided in the part that resides between the two commas.he/ll/o_/he/ll/o,/12/3-/wo/rl/d5/67/-h/el/lo/wo/rl/d1/23/45/6,/wo/rl/d1/23/4-/he/ll/o0/98/76/
How to avoid that an insertion pattern using sed is applied to the middle of a string?
sed
I can do it like:sed 's|\(,[^,]*,\)\{0,1\}\([^,]\{1,2\}\)|\1/\2|g' <<\IN                                     hello_hello,123-world567-helloworld123456,world1234-hello09876IN...which prints.../he/ll/o_/he/ll/o,123-world567-helloworld123456,/wo/rl/d1/23/4-/he/ll/o0/98/76So most of the changes made are done to the second s///ubstitution - but that's because I removed all of the first.So the biggest part of your problem was that you were simply telling sed to substitute in a / after every two characters - the . dots mean any char and the g means global - or all.The second biggest part was that the first substitution was not helping you - and was completely unnecessary.More than that though, you were also inserting an extra comma in the first substitution - so after I'd get the first bit straightened out, I was still running into extra fields. Look:\(,[^,]*,\)\{0,1\}\([^,]\{1,2\}\)|\1/\2That's the substitution statement that worked for me, and heres why: \(,[^,]*,\)\{0,1\} - in a global context you have to be careful to get only as much as you need. You were substituting for every two chars and so that's what you got - sed is greedy. This is referenced first - which is important - because as sed reads left to right it will usually just insert a slash between every two sequential not comma chars, but it if it encounters a comma it will read in up to the next it finds and save the whole block to \1 without inserting any slashes at all.\([^,]\{1,2\}\) - You can't use the . dots here - they will match a comma and so you'll just wind up writing in the slashes after you skip a delimiter. You need to explicitly exclude commas. And so that is what this does - every sequence of 1 or 2 of them - though sed will always pull the largest one of those numbers that it might.One difference I can see between this and that in your example is the first slash here is at the head of the string and there is no trailing slash, whereas yours does the opposite. To remedy that, as needed:...;s|^/\(.*/.\)/*$|\1/|...