tags:

views:

35

answers:

3

Hello stack overflow,

Does anyone know how to replace 'line a' with 'line b' and 'line b' with 'line a' in a text file using the sed editor? I can see how to replace a line in the pattern space with a line that is in the hold space (i.e. /^Paco/x or /^Paco/g), but what if I want to take the line starting with Paco and replace it with the line starting with Vinh, and also take the line starting with Vinh and replace it with the line starting with Paco. Let's assume for starters that there is one line with Paco and one line with Vinh, and that the line Paco occurs before the line Vinh. Then we can move to the general case.

Thanks in advance,

David

A: 

A simple example from the GNU sed texinfo doc:

Note that on implementations other than GNU `sed' this script might
easily overflow internal buffers.

 #!/usr/bin/sed -nf

 # reverse all lines of input, i.e. first line became last, ...

 # from the second line, the buffer (which contains all previous lines)
 # is *appended* to current line, so, the order will be reversed
 1! G

 # on the last line we're done -- print everything
 $ p

 # store everything on the buffer again
 h
smilingthax
Thanks smilingthax. Your answer shows me how to reverse the lines in a file, but I'd like to just swap two lines in the file.
David
You can use the other commands like conditional branch (t) and labels to do that. But I'd prefer perl or something similiar for that job. Another possibility is replacing '\n' with some special character before using sed and treating everything as one long line, and in the end back-substitute the chars (e.g. with tr).
smilingthax
If anyone has a working example of how to do it with sed, that would be the ticket. Thanks.
David
A: 

try this awk script.

s1="$1"
s2="$2"
awk -vs1="$s1" -vs2="$s2" '
{ a[++d]=$0 }
$0~s1{ h=$0;ind=d}
$0~s2{
 a[ind]=$0
 for(i=1;i<d;i++ ){ print a[i]}
 print h
 delete a;d=0;
}
END{ for(i=1;i<=d;i++ ){ print a[i] } }' file

output

$ cat file
1
2
3
4
5

$ bash test.sh 2 3
1
3
2
4
5

$ bash test.sh 1 4
4
2
3
1
5

Use sed (or not at all) for only simple substitution. Anything more complicated, use a programming language

ghostdog74
Thanks Ghostdog. Great script. Thing is, I'm just learning sed, and this is one of the questions I need to answer (Ellie Quigley, Linux by Example). So if anyone has a working sed example, that would be great.
David
A: 
#!/bin/sed -f
/^Paco/ {
:notdone
  N
  s/^\(Paco[^\n]*\)\(\n\([^\n]*\n\)*\)\(Vinh[^\n]*\)$/\4\2\1/
  t
  bnotdone
}

After matching /^Paco/ we read into the pattern buffer until s// succeeds (or EOF: the pattern buffer will be printed unchanged). Then we start over searching for /^Paco/.

smilingthax
Thanks smilingthax! It works. You are a genius!
David