11

I simply want to do following

replace

EXTRATHING {
};

by

SOMETHING {};

in inputfile. For this, I tried

sed -e 's/EXTRATHING {\n};/SOMETHING/' input_file.txt  >outfile.txt

This doesn't work. Can someone suggest what would be the correct way of doing this with sed?

Michael J. Barber
  • 24,518
  • 9
  • 68
  • 88
bbv
  • 501
  • 1
  • 5
  • 14

6 Answers6

6
sed -n '1h;1!H;${;g;s/EXTRATHING {\n};/SOMETHING {};/g;p;}' input_file.txt

would do it.

The problem with this is that it stores the whole input string in sed's buffer.

See sed and Multi-Line Search and Replace for more info, and a more efficient version.

Bertrand Marron
  • 21,501
  • 8
  • 58
  • 94
  • This is a great answer. You show the correct way to do it in `sed`, but you also describe the drawbacks. Using `se`d for multi-line matching with huge files can be computationally expensive. In this situation (really big files), I think the best thing to do is use a `perl` solution, such as the [one](https://stackoverflow.com/a/27939898/6505499) by @MasterYoda. I've personally made the change to `perl 0777` for multi-line matching rather than `sed -n`. I resisted it for a while, but the benefits are worth it. – bballdave025 Sep 27 '18 at 18:45
3
 sed -i.bak '/EXTRATHING/{N;s//SOMETHING/;s/\n//}' input_file.txt
Sidharth C. Nadhan
  • 2,191
  • 2
  • 17
  • 16
2

sed -e '/begin/,/end/{s/begin/replacement/p;d}'

BCS
  • 75,627
  • 68
  • 187
  • 294
  • 4
    Can you explain this please? Thanks. :) – Ray Sep 07 '13 at 12:18
  • 2
    I think it was based on a bad understanding of the question. – BCS Sep 07 '13 at 15:49
  • No no, this is exactly what I came here to find. For the sequence of rows that start with `begin` and end with `end`, delete them all, but for the line that contains `begin` also emit `replacement`. In terms of the question the line would be `sed -e '/EXTRATHING {/,/};/{s/EXTRATHING {/SOMETHING {};/p;d}'` – clacke Apr 04 '19 at 15:37
2

It's difficult to do it in sed, one needs to write subscripts. However, you can use a one-liner using perl:

perl -0777 -pe 's/EXTRATHING {\n/SOMETHING {/g' input_file.txt > outfile.txt

where -0777 is record separator (endline in text files) -p runs command for all file and prints on screen -e says it's a one line command

bballdave025
  • 1,347
  • 1
  • 15
  • 28
Master Yoda
  • 176
  • 1
  • 8
  • Even though this answer doesn't describe how to perform the answer in `sed`, I believe it to be the best answer. Multi-line matching is not only much easier in `perl`, but takes up less computational resources. – bballdave025 Sep 27 '18 at 18:41
  • Just to clarify, the 'subscripts' to which you're referring are the parts of code within curly brackets, right? For example, the `${;g;s/EXTRATHING {\n};/SOMETHING {};/g;p;}` in the [answer](https://stackoverflow.com/a/8164741/6505499) by @BertrandMarron is what you call a subscript, if I understand correctly. Please let me know if this is what you meant. – bballdave025 Sep 27 '18 at 18:44
1
perl -lne 's/\s*};\s*$/SOMETHING{};/g if(/\s*};\s*$/);$f=0;if(/EXTRATHING {\s*$/){next;$f=1}else{print}' your_file

tested below:

> cat temp
fjbwjfbw
wefjkbwjk
jbefwejr
EXTRATHING {
};
ghekg
jhgjk
wefjkwngk
EXTRATHING {
  };
jbgvjnrg
jbfw
wefnkwk
EXTRATHING {
};
> perl -lne 's/\s*};\s*$/SOMETHING{};/g if(/\s*};\s*$/);$f=0;if(/EXTRATHING {\s*$/){next;$f=1}else{print}' temp
fjbwjfbw
wefjkbwjk
jbefwejr
SOMETHING{};
ghekg
jhgjk
wefjkwngk
SOMETHING{};
jbgvjnrg
jbfw
wefnkwk
SOMETHING{};
> 

if you want to change the file inline . add a -i flag. like :

perl -i -lne '.......' your_file
Vijay
  • 65,327
  • 90
  • 227
  • 319
0

This might work for you:

 sed '/^EXTRATHING {/,/^};/c\SOMETHING{}' input_file.txt >output_file.txt

or if you want to edit the original file:

sed -i '/^EXTRATHING {/,/^};/c\SOMETHING{}' input_file

EDIT: as requested here's an example:

cat <<! | sed '/^EXTRATHING {/,/^};/c\SOMETHING{}'
> aaa
> EXTRATHING {
> };
> bbb
> EXTRATHING {
> };
> ccc
> !
aaa
SOMETHING{}
bbb
SOMETHING{}
ccc

EDIT: If the first and last addresses are consecutive lines, use this:

# cat <<\! | sed '/^EXTRATHING {/{N;s/^EXTRATHING {\n};/SOMETHING{}/}'
> aaa
> EXTRATHING {
> bbb
> };
> ccc
> EXTRATHING {
> };
> ddd
> !
aaa
EXTRATHING {
bbb
};
ccc
SOMETHING{}
ddd

Another way (perhaps easier?):

echo -e "EXTRATHING {\n};" | sed '$!N;s/^EXTRATHING {\n};/SOMETHING {};/;P;D'
SOMETHING {};
potong
  • 55,640
  • 6
  • 51
  • 83
  • care to post your example that this works ;-)? I just get the original doc returned.. Good luck. – shellter Nov 17 '11 at 21:53
  • Thanks @potong. However, your command will also remove the original pattern if there are some other lines between "EXTRATHING {" and "};". I do not want those to be replaced. So, the following should not be replaced "EXTRATHING {\n something\n};". – bbv Nov 18 '11 at 05:44
  • Thanks, I see your code works with the sed 4*, but not with the un-versioned version that I have in UWIN. Are you using a range expression to capture the two lines? i.e. `/x/,/y/`? Good luck to all. – shellter Nov 18 '11 at 05:46