PrOpoLo
PrOpoLo

Reputation: 113

Insert part of a file into another file at a specific location

I am trying to copy a part of a file into another file at a specific location.

I can't use sed -i '/match/r fileToInsert' file because I want to insert only some content of fileToInsert, not the whole file.

My fileToInsert is as follow:

 <?xml version="1.0" encoding="ISO-8859-1"?>                                                                                                                                                  
 <!-- OriginalName: test.xml -->                                                                                                                                                        
 <ListModes>
 ...

I tried this:

sed -i "/match/a$(sed -n '2,3p' fileToInsert)" file

But it does not work either because fileToInsert is an xml file and sed chokes on the second line when encountering the opening "<":

sed -e expression #1, char 59: unknown command: `<'

(it works if I try with just one line though).

Is there any way to achieve what I want on linux ? Could be with sed, awk or any other existing utility on a redhat distribution.

Upvotes: 2

Views: 334

Answers (4)

petrus4
petrus4

Reputation: 614

echo "2,3W file" | ed -s fileToInsert

Upvotes: 0

anubhava
anubhava

Reputation: 784938

awk can do this completely in one single command:

awk '
FNR == NR {
   if (FNR >= 2 && FNR <= 3)
      s = s $0 ORS
   next
}
1
/match/ {
   printf "%s", s
}' fileToInsert file

Showing find + awk solution as commented below:

cat ins.awk

FNR == NR {
   if (FNR >= 2 && FNR <= 3)
      s = s $0 ORS
   next
}
1
/match/ {
   printf "%s", s
}

Run it as:

find . -type f -exec awk -f ins.awk fileToInsert {} \;

Update: In response to this comment:

To be totally complete, if I wanted to insert only after the first match (or for the first nth matches), how would I do that please ?

You can use:

FNR == NR {
   if (FNR >= 2 && FNR <= 3)
      s = s $0 ORS
   next
}
1
!done && /match/ {
   printf "%s", s
   ++done
}

Or to insert after first MAX matches only change last block to:

n <= MAX && /match/ {
   printf "%s", s
   ++n
}

Upvotes: 8

Paul Hodges
Paul Hodges

Reputation: 15246

Perhaps less elegent, but sed substitutions can also run internal commands in subshells with the e flag.

$: cat 1
1
2
3
4
5

$: cat a
a
b
c
d
e

edited

$: sed '/3/{p;s/.*/sed -n 2,3p a/e}' 1
1
2
3
b
c
4
5

Not sure if that feature is GNU only. I think this one is - can use an e command as a standalone. If you do that you need to explicitly print the original line first, then execute the subshell, then delete it to prevent duplicate output - which means grouping multiple commands, and this needs an actual newline after the e command instead of just a semicolon. See below.

$: sed '/3/{p;e sed -n 2,3p a
d}' 1
1
2
3
b
c
4
5

Upvotes: 1

Fravadona
Fravadona

Reputation: 16885

I would try with a bash process substitution

#!/bin/bash

sed -i '/match/r '<(sed -n '2,3p' fileToInsert) file

Upvotes: 6

Related Questions