print only changed line with sed after double substition
Hi,
As the title says, I'm trying to print only the lines that have been changed with sed after a double substitution. This is the text file: Code:
The grand old Duke of York So for instance, sed -e '/s/up/UP' -e 's/down/DOWN' file.txt will display the whole file, including the lines which haven't been altered. sed -n -e 's/up/UP/p' -e 's/down/DOWN/p' file.txt won't work either, because lines containing both 'up' and 'down' are going to be displayed twice (once for each substition). So how should I go about this problem? |
Use regex to do the substitution for both in one stanza.
|
I can only think of the\U option, which turns what it matches into uppercase. I don't want the solution, but I'd like to know in principle how I could actually use regex for two different strings and apply the same action to both. I was thinking of something like 's/"up|down"/\U/', which doesn't work because it interprets them literally. And neither would \| work between "up" and "down" :)
|
Quote:
If you are only ever going to be using GNU sed then you can do it more concisely with T instead and skip the jumping. |
Perhaps you shouldn't be so keen to reject options. You might be pleasantly surprised.
Some tips if I might: - look at "-r" - check the (GNU) doco for the first few sentences describing the "s" command. Particularly re the matched portion of the pattern space. (no need for branching in this case) |
I'm not rejecting options. After all -n and -e are options. It's just that you suggested using regex and still don't know exactly how I could solve the problem through regex alone. Yes, actually, I've already looked at -r, and sed does interpret | as or, but that doesn't seem to be the right solution. Anyway, I haven't heard of t, b, or :, so I'll have to read a little bit more.
|
Think like this...
Code:
$ sed -rn /ADDRESS/s/MATCH/REPLACE/gp I had to use the ADDRESS to get only the desired line(s), then using the not so subtle 's' hint provided by syg00 and a previously mentioned operator provided the right result. Not to give everything away, here is an obfuscated example with the text in ud.txt: Code:
$ sed -rn '/.../s/up|down/.../gp' ud.txt |
With the t and d commands
Code:
sed ' Code:
awk 'sub(/up/,"UP") && sub(/down/,"DOWN")' file.txt |
Quote:
|
This is what I came up with:
Code:
sed -nE '/up|down/s/up|down/\U/gp' duke.txt By the way, I think the correct option was -E, not -r, in order to make sed interpret extended regex. I was referring to -E when I said that sed was eventually interpreting | as "or". |
You'll probably use an ampersand & instead of \U
Here's another alternative: Code:
sed -e '/down/s/up/&/; t; d;' duke.txt The t is a conditional jump. When used without a destination it defaults to a jump to the end of the sed script. Thus if the // pattern matches AND the s/// substitution succeeds, hop over the command to delete the line. |
I don't insist doing it with regex (only). syg00 had suggested it at the beginning of the thread and that's why I was curious. I'm fine with using sed options. The question is, why doesn't \U work? I've seen several examples on the internet.
P.S. Only now did I see that on mac it works only with -E (for extended regex), but on Centos it seems to be working with -r (only?). |
In which context have you seen \U mentioned? I don't see it in the regex manual or in the manual for sed itself.
Code:
man 7 regex Code:
man perlre |
https://www.gnu.org/software/sed/man...s_0022-Command
And yes, I was working with sed on mac, and now I see it's behaving slightly differently on Centos 7 when using \U. It doesn't interpret it as a literal \U, but it still doesn't work. It simply deletes both matches ("up" and "down"). |
If you want portability you'll need to give up on \U in sed scripting and stay closer to POSIX.
Code:
sed 's/up/UP/g; t up; d; b; :up { s/down/DOWN/g; t; d; }' duke.txt |
All times are GMT -5. The time now is 01:14 AM. |