sed, insert file before last line

The following inserting file method for sed used to be working, even before last line, but not any more. Is it a bug in the current sed?

Demo of inserting file method with sed:

mkdir /tmp/test
printf '%s\n' {1..3} > /tmp/test/f1
printf '%s\n' {one,two,three,four,five,six,seven,eight,nine,ten} > /tmp/test/f2

$ cat /tmp/test/f2 | sed -e "/nine/r /tmp/test/f1" -e //N
one
two
three
four
five
six
seven
eight
1
2
3
nine
ten

$ head -9 /tmp/test/f2 | sed -e "/nine/r /tmp/test/f1" -e //N
one
two
three
four
five
six
seven
eight
nine
1
2
3

$ cat /tmp/test/f2 | sed -e "/ten/r /tmp/test/f1" -e //N
one
two
three
four
five
six
seven
eight
nine
ten
1
2
3

$ sed --version
GNU sed version 4.2.1
... 

I.e., the inserting file before the line method works everywhere except the last line. It used to be working before. Is it a bug in the current sed?

Thanks


Solution 1:

Since you're on gnu sed you could use

'e [COMMAND]'
     This command allows one to pipe input from a shell command into
     pattern space.

on the la$t line:

sed '$e cat insert.txt' file

With ed (replace ,p with w if you want to edit-in-place):

ed -s file<<IN
- r insert.txt
,p
q
IN

or

ed -s file <<< $'-1 r insert.txt\n,p\nq\n'

When ed reads file the current address is set to the la$t line. - (or -1) sets the current address to one line before (i.e. $-1) and r reads in insert.txt to after the current line. ,p prints the content of the text buffer (as I said, replace with w to save changes) and q quits editor.

Solution 2:

According to your comment you "HAVE TO match against the last line", so I would consider using the $ (last line) and i (insert command) in sed. For example:

sed '$ i\INSERT BEFORE LAST LINE' number.txt
1
2
3
4
INSERT BEFORE LAST LINE
5

Just make sure that the file doesn't have an empty line as the last line and it should work. Note the the space between the dollar sign and the i and the backslash (\) after the i. This will insert the text after the backslash to the last line without needed a /pattern/ for the last line.

NOTE: This command will only add one line of text before the final line, not a file. If you want to insert the contents of a file before the last line.

If you want to add an entire file (and you don't if it's in sed) I would use this:

    head -n-1 first_file.txt && cat inserted_file.txt && tail -n1 first_file.txt 

This should display everything except the last line, then cat the the inserted_file.txt and then display the last line of the first_file.txt.