3

Hi I am new to this forum. I want to use SED to replace an expression on even lines of a file. My problem is that I cannot think f how to save the changes in the original file (i.e, how to overwrite the changes in the file). I have tried with :

sed -n 'n;p;' filename | sed 's/aaa/bbb/'

but this does not save the changes. I appreciate your help on this.

regex99
  • 97
  • 3
  • 9
  • http://stackoverflow.com/questions/10829514/how-do-i-run-the-sed-command-with-input-and-output-as-the-same-file/10834267#10834267 – William Pursell Jun 01 '12 at 20:55
  • @regex99 do not forget to accept your favorite answer! You can accept an answer by clicking in the big "V" just in the left of the answer. For more info, see [this text](http://stackoverflow.com/faq#howtoask). – brandizzi Jun 14 '12 at 04:02

4 Answers4

8

Try :

sed -i '2~2 s/aaa/bbb/' filename

The -i option tells sed to work in place, so not to write the edited version to stout and leave the original file be, but to apply the changes to the file. The 2~2 portion is the address for the lines sed should apply the commands. 2~2 means edit only even lines. 1~2 would edit only odd lines. 5~6 would edit every fifth line, starting at line 5 etc...

brandizzi
  • 26,083
  • 8
  • 103
  • 158
Mithrandir
  • 24,869
  • 6
  • 50
  • 66
  • Hi Mithrandir. Thanks a lot. It works perfectly. Could you hint on how this one-liner works ? what if I had to apply to odd lines? – regex99 Jun 01 '12 at 19:56
5

@Mithrandir's answer is an excellent, correct and complete one.

I will just add that the m~n addressing method is a GNU sed extension that may not work everywhere. For example, not all Macs have GNU sed, as well as *BSD systems may not have it either.

So, if you have a file like the following one:

$ cat f
1   ab
2   ad
3   ab
4   ac
5   aa
6   da
7   aa
8   ad
9   aa

...here is a more universal solution:

$ sed '2,${s/a/#A#/g;n}' f
1   ab
2   #A#d
3   ab
4   #A#c
5   aa
6   d#A#
7   aa
8   #A#d
9   aa

What does it do? The address of the command is 2,$, which means it will be applied to all lines between the second one (2) and the last one ($). The command in fact are two commands, treated as one because they are grouped by brackets ({ and }). The first command is the replacement s/a/#A#/g. The second one is the n command, which gets, in the current iteration, the next line, appends it to the current pattern space. So the current iteration will print the current line plus the next line, and the next iteration will process the next next line. Since I started it at the 2nd line, I am doing this process at each even line.

Of course, since you want to update the original file, you should call it with the -i flag. I would note that some of those non-GNU seds require you to give a parameter to the -i flag, which will an extension to be append to a file name. This file name is the name of a generated backup file with the old content. (So, if you call, for example, sed -i.bkp s/a/b/ myfile.txt the file myfile.txt will be altered, but another file, called myfile.txt.bkp, will be created with the old content of myfile.txt.) Since a) it is required in some places and b) it is accepted in GNU sed and c) it is a good practice nonetheless (if something go wrong, you can reuse the backup), I recommend to use it:

$ ls
f
$ sed -i.bkp '2,${s/a/#A#/g;n}' f
$ ls
f  f.bkp

Anyway, my answer is just a complement for some specific scenarios. I would use @Mithrandir's solution, even because I am a Linux user :)

Community
  • 1
  • 1
brandizzi
  • 26,083
  • 8
  • 103
  • 158
0

This might work for you:

sed -i 'n;s/aaa/bbb/' file
potong
  • 55,640
  • 6
  • 51
  • 83
-1

Use sed -i to edit the file in place.

sloth
  • 99,095
  • 21
  • 171
  • 219
Ed Manet
  • 3,118
  • 3
  • 20
  • 23
  • Hi Ed Manet. Could you give an example code ? if I put the -i option in the first part (before pipeline) I do not get any change and if I put it after the pipeline, I get the error: sed: no input files – regex99 Jun 01 '12 at 19:52