3

I am trying to replace lines from one file (file1) with the same number of lines and in same positions from another file(file2). I found

sed -n 1,5p file2

would extract the first five lines from file2. How can i use these lines and replace the first five lines in file1?

3

Bit of a cheat, (not pure sed), using sponge:

{ sed -n 1,5p file2 ; sed -n '6,$p' file1 } | sponge file1
  • Thanks a lot, is there a way to avoid sponge, i am working on a server and they don't seem to have moreutils installed – Pavan Nov 20 '17 at 7:30
  • 1
    @Pavan, This should work: { sed -n 1,5p file2 ; sed -n '6,$p' file1 } > file3 ; mv file3 file1 – agc Nov 20 '17 at 7:45
8

For in-place editing with GNU sed, there's the -i option. The Read line command, (which reads one line from a named file, then each line after that when run again), is useful here. Two line version:

sed -i '1,5{R file2
        d}' file1

Notes:

  • Read line's output is not changed by the delete that follows. R inserts each line from file2 after d deletes a line from file1. The d cannot go first, (if it did, the R command would not be run, d is like next in awk)

  • The Read line (like all commands taking a file name) requires the filename be delimited by a linefeed. The usual ; command separator is ignored, R interprets R file2; as a filename ending with a literal ";". The same with spaces, R interprets R file2 ; as a filename ending with a literal ";"

  • R is not affected by -i, so file2 won't be changed.

To fit that on one line, one can pass two -expressions which sed joins with linefeeds to form the sed script:

sed -i -e '1,5{R file2' -e 'd}' file1

Otherwise, you don't need sed:

{ head -n 5 file2; tail -n +6 file1; } > file3

In the general case, to replace $x1 to $y1 lines of file1 with $x2 to $y2 lines of file2:

sed "$x2,\$!d;$y2 q" file2 | sed -i -e "$x1 r /dev/stdin" -e "$x1,$y1 d" file1

Or:

{
  head -n "$((x1 - 1))"
  tail -n "+$x2" < file2 | head -n "$((y2 - x2 + 1))"
  tail -n "+$((y1 - x1 + 2))"
} < file1 > file3 
  • This is the best solution. I've added some explanatory notes about the R command, since its syntax is not obvious or very well documented. – agc Nov 20 '17 at 14:43
  • 1
    @agc - the R (just like r) doesn't operate on the pattern space - saying it's "immune to d" is a bit off imo... which brings us to your next statement: "The d cannot go first, (if it does R outputs nothing);". In fact, anything that follows after the d is no longer executed because d restarts the cycle. So if R comes after the d it cannot output "nothing" since it's not even executed. I'm not sure I get the part with "R is not affected by -i" ... – don_crissti Nov 20 '17 at 14:56
  • Other working one line variants: sed -i -e 1,5\{R\ file1 -e d\} file2 and sed -i -e '1,5R file1' -e '1,5d' file2 and sed -i -e 1,5R\ file1 -e 1,5d file2. – agc Nov 20 '17 at 14:58
  • @don_crissti, Thanks. Prior to your useful comment I'd wrongly supposed that something like seq 5 | sed '1{d;d}' would not have output a 2. The bit about -i is to clarify that in-place edits do not change files only named by Read line. – agc Nov 20 '17 at 15:19
0

How about using a tmp file?

sed -n ‘1,5p’ file2 > file3 ; sed ‘1,5d’ file1 >> file3 ; mv file3 file1
  • yeap, it works fine @agc has a similar solution – Pavan Nov 20 '17 at 7:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.