10

I'm trying to insert a file content before a given pattern

Here is my code:

sed -i "" "/pattern/ {
i\\ 
r $scriptPath/adapters/default/permissions.xml"
}" "$manifestFile"

It adds the path instead of the content of the file.

Any ideas ?

ridan
  • 858
  • 3
  • 11
  • 24

5 Answers5

20

In order to insert text before a pattern, you need to swap the pattern space into the hold space before reading in the file. For example:

sed "/pattern/ {
         h
         r $scriptPath/adapters/default/permissions.xml
         g
         N
     }" "$manifestFile"
Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • The script has to be double quoted, otherwise $scriptPath won't be expanded. Could you please explain why is N needed at the end? – hipe Jun 28 '12 at 15:53
  • @hipe The r command only queues the read for insertion into the output stream. It doesn't actually read anything until the end of the cycle or when the next line is read. Without N the file wouldn't be inserted until after the pattern space was printed, making it function as an append rather than an insert. It's *very* non-intuitive. – Todd A. Jacobs Jun 28 '12 at 16:07
  • 2
    Seems sed is very picky with the 'r' command. According to http://www.linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/sedfaq5_008.html: "Any additional characters before or after the filename are interpreted as part of the filename." I tried `r someFile.txt # insert content of ...` and it failed silently. – vscharf Apr 15 '14 at 13:42
  • 3
    This works fine as long as `pattern` is _not_ on the last line. – don_crissti Mar 30 '15 at 18:01
  • Hi, Todd and @vscharf, I found "h" & "g" are ommitable. I wrote this one-liner( https://stackoverflow.com/a/56182135/26736 ). Thanks ! – benok May 17 '19 at 08:26
5

Just remove i\\.

Example:

$ cat 1.txt
abc
pattern
def

$ echo hello > 2.txt

$ sed -i '/pattern/r 2.txt' 1.txt

$ cat 1.txt
abc
pattern
hello
def
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144
3

I tried Todd's answer and it works great,

but I found "h" & "g" commands are ommitable.

Thanks to this faq (found from @vscharf's comments), Todd's answer can be this one liner.

sed -i -e "/pattern/ {r $file" -e 'N}' $manifestFile

Edit: If you need here-doc version, please check this.

benok
  • 688
  • 1
  • 6
  • 21
1

I got something like this using awk. Looks ugly but did the trick in my test:

command:

cat test.txt | awk '
/pattern/ {
    line = $0;
    while ((getline < "insert.txt") > 0) {print};
    print line;
    next
}
{print}'

test.txt:

$ cat test.txt
some stuff
pattern
some other stuff

insert.txt:

$ cat insert.txt
this is inserted file
this is inserted file

output:

some stuff
this is inserted file
this is inserted file
pattern
some other stuff
bcelary
  • 1,827
  • 1
  • 17
  • 17
0

CodeGnome's solution don't work, if the pattern is on the last line.. So I used 3 commands.

sed -i '/pattern/ i\
        INSERTION_MARKER
        ' $manifestFile
sed -i '/INSERTION_MARKER/r $scriptPath/adapters/default/permissions.xml' $manifestFile
sed -i 's/INSERTION_MARKER//' $manifestFile
Sinhyeok
  • 46
  • 4
  • i found it most straightforward to use vim for this: `vim "$fileToEdit" <<< ':$-1 r'"$fileToInsert"$'\n:wq'` – Sam May 08 '19 at 14:32