Reputation: 113
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
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
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
$: 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
Reputation: 16885
I would try with a bash process substitution
#!/bin/bash
sed -i '/match/r '<(sed -n '2,3p' fileToInsert) file
Upvotes: 6