LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Need sed help: s/ command won't replace two occurrences of pattern on same line (https://www.linuxquestions.org/questions/programming-9/need-sed-help-s-command-wont-replace-two-occurrences-of-pattern-on-same-line-775955/)

GrapefruiTgirl 12-15-2009 10:33 PM

Need sed help: s/ command won't replace two occurrences of pattern on same line
 
Here's the actual line of code, which exists in a bash script:

Code:

blah blah blah=$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]})
I want to replace instances like this:
Code:

$(eval echo \${$i2[2]})
with this:
Code:

$(eval echo \$${i2}_3)
Using this:
Code:

sed 's~\(\$(.*\\\$\){\$\([0-9a-zA-Z]*\)\([[]\)\([0-9a-zA-Z]*\)\([]]\)})~\1\${\2}_\4)~g'
Which works great when there's only ONE of the pattern on the line. But in a case like the "actual line" I posted first, where there are two patterns, separated by a slash, only ONE gets replaced :scratch:

Watch:
Code:

shell# echo '$(eval echo \${$i2[2]})' | sed 's~\(\$(.*\\\$\){\$\([0-9a-zA-Z]*\)\([[]\)\([0-9a-zA-Z]*\)\([]]\)})~\1\${\2}_\4)~g'
$(eval echo \$${i2}_2) <--replaced!

shell# echo '$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]})' | sed 's~\(\$(.*\\\$\){\$\([0-9a-zA-Z]*\)\([[]\)\([0-9a-zA-Z]*\)\([]]\)})~\1\${\2}_\4)~g'
$(eval echo \${$i2[2]})/$(eval echo \$${i2}_3)
    ^^^ not replaced ^^        ^^^replaced^^^

Why?? There must be (among many other things) something I'm not knowing about sed, that's causing this.

NOTES:
-- I'm currently using the ~ (tilde) as the separator in the sed command. It doesn't matter, I've used / ~ and % with no difference.
-- As a test, I tried putting a different character(s) in the middle of the original pattern instead of the / but that made no difference.
-- I've come up with various similar but slightly different regexs that will do this replacement, but they all have had this same result.
-- I tried the sed single-quoted, double-quoted, and unquoted; the latter fails to execute, and the formers both work as described here: wrong.

Please help! :banghead:

Sasha

GrapefruiTgirl 12-15-2009 10:41 PM

OK, it just occurred to me that as a work-around, I can execute the sed -i against the file I'm editing, and then execute the sed AGAIN against the edited file, and with two passes at it like that, the line(s) in question will get sedded. But this doesn't address why it doesn't work in one pass.

GrapefruiTgirl 12-15-2009 10:44 PM

WTF :confused: now it's working... This is ridiculous. I put some more of the actual line, into the pattern to match (which I've done loads of times by now) and this time, it works:

Quote:

echo '$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]})' | sed 's~\(\$(eval echo \\\$\){\$\([0-9a-zA-Z]*\)\([[]\)\([0-9a-zA-Z]*\)\([]]\)})~\1\${\2}_\4)~g'

$(eval echo \$${i2}_2)/$(eval echo \$${i2}_3) <--both occurrences fixed.
Phooey.....

pixellany 12-15-2009 11:04 PM

I did it like this:

First, I assumed that the non-fixed portions were just "i2" (regex = [a-z][0-9]) and "2" (regex= [0-9]) These are the only pieces that I put into backreferences.

I put the string into a file, and:
Code:

mherring@Ath ~]$ more sasha
$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]})
[mherring@Ath ~]$ sed 's%\${\$\([a-z][0-9]\)\[\([0-9]\)\]}%\$\${\1}_\2%g' sasha
$(eval echo \$${i2}_2)/$(eval echo \$${i2}_3)
[mherring@Ath ~]$


GrapefruiTgirl 12-15-2009 11:07 PM

Egads! So much simpler to do it that way :) -- a whole lot less freaking s*** in the regex, that's for sure :/ though this is a big script I'm batch-editing with sed, and there are a lot of slightly different incarnations of these crazy eval/echo/array things, so maybe I'm on the safe side to include the more details in the regexes -- either way, thanks for that simpler suggestion.

Thanks.
Sasha

ntubski 12-15-2009 11:19 PM

The problem with your original pattern was using ".*": sed regex's are greedy so

Code:

sed 's~\(\$(.*\\\$\){\$\([0-9a-zA-Z]*\)\([[]\)\([0-9a-zA-Z]*\)\([]]\)})~\1\${\2}_\4)~g'
 matches
blah blah blah=$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]})
 rather than
blah blah blah=$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]})
 as you intended


ghostdog74 12-15-2009 11:23 PM

you are doing this for one time only , right?
Not that it matters, but i would still recommend not doing this in shell but a programming language. it will benefit you in future.

GrapefruiTgirl 12-16-2009 02:08 AM

:)

Doing 'what' exactly for one time only? This sed thing? Well, more than one time, yes, but all for one occasion, that being the process of converting this 2300+ line shell program over from using arrays, to NOT using arrays, so it can become portable. I'm using this concept we discussed over there: http://www.linuxquestions.org/questi...rings.-775622/ to replace the arrays.

And I am tickled to report that as of 20 minutes ago, IT IS WORKING!!! :D I'm done! The whole script has been converted, thanks in large part to a sequence of sed's more-or-less like the situation above, and some finishing touches with search+replace in my text editor. The script now runs in Dash too!!

As for "other languages", as much as I'd really love to be an excellent C programmer (for the sake of argument, but it could be <whatever> language), AND while there may/probably/likely be languages better suited to do some things that I do, I actually really enjoy the challenge of creating stuff in shell :) and besides, the amount of time I would spend becoming competent enough in another language to do something useful, could be better spent IMHO getting better in shell. Like they sometimes say, "Go with what you know.".

My ability in C for example is enough that I can debug most problems I encounter with pre-existing code, and I've sent a couple very tiny patches to the linux kernel, but I don't pretend for a second that I can write my own program from scratch in C. I put a tiny bit of time into it, and have lots of reading material, but I don't spend enough time to expect to become competent with it.

Sasha!!


All times are GMT -5. The time now is 02:24 AM.