Insert text N lines before the last line
Solution 1
Using ed
:
$ printf '$-1i\nNew line\n.\n,p\n' | ed -s file
1
2
3
New line
4
5
The ed
editing script:
$-1i
New line
.
,p
This first moves to the line one line up from the end ($-1
) and inserts (i
) new contents above that line. The contents inserted is ended with the single dot (it's allowed to be multiple lines). The last ,p
displays the complete modified buffer on the terminal.
You may redirect this to a new file, or you may write it back to the original file using
printf '$-1i\nNew line\n.\nw\n' | ed -s file
(the ,p
is changed to w
).
This latter is also how you would similarly use ex
for this job:
printf '$-1i\nNew line\n.\nw\n' | ex -s file
ed
and ex
are standard line-oriented editors (as opposed to full-screen editors) that should come with your system. Note that -s
means different things to each, but is appropriate for both when doing batch mode editing tasks like this.
-
ed
. "Shell and utilities". Base specifications. IEEE 1003.1:2017. The Open Group. -
ex
. "Shell and utilities". Base specifications. IEEE 1003.1:2017. The Open Group.
Further reading:
- Dale Dougherty and Tim O'Reilly (1987). "Advanced Editing". Unix Text Processing. Hayden Books.
Solution 2
It can be done by simple head
and tail
:
$ output=$(head -n -2 file ; echo 'new line' ; tail -2 file)
$ echo "$output" > file
As mentioned in comments , it will eat any trailing blank lines. So , for preserving trailing blank lines,
$ head -n -2 file >> file.tmp
$ echo 'new line' >> file.tmp
$ tail -2 file >> file.tmp
$ mv file.tmp file
or single liner
$ head -n -2 file >> file.tmp ; echo 'new line' >> file.tmp; tail -2 file >> file.tmp ; mv file.tmp file
Solution 3
You could use GNU sed
too:
sed -zE 's/(\n[^\n]*){3}$/\nNew-line&/' infile
Insert a line New-line
in third last line of the file (Insert a line two lines before the last line).
This (\n[^\n]*){3}$
matches \n
ewline followed by anything but not a \n
ewline and maximum 3 times from end of the file where -z
option casing sed to read a file as a single line (separate lines by NUL characters). So it will match below only (between asterisks I highlighted):
3*\n
4\n
5\n*
Portability, you would use:
sed -e ':t;N;$!bt; s/\(\n[^\n]*\)\{2\}$/\nNew-line&/' infile
if still your sed
cannot handle a \n
ewline in replacement part, you can have actual newline or press Ctrl+V followed by Enter which will print ^M
control characters of enter key:
sed -e ':t;N;$!bt; s/\(\n[^\n]*\)\{2\}$/\
New-line&/' infile
How it works
The N
append each line sed read to the pattern space followed by a new line added until all lines read. The :t
defines a label and $!bt
telling sed jump to the label called t
as long as it's not end of the file.
Solution 4
This one should be quite robust against contents of the inserted line, but requires the file to be scanned twice (wc
for the first pass).
sed "$(($(wc -l < yourfile)-$N))a"'new line' yourfile
Solution 5
Following awk
could help too.
awk -v line=$(wc -l < Input_file) -v val="new_line" 'FNR==(line-1){print val} 1' Input_file
Related videos on Youtube
αғsнιη
SeniorDevOpsEngineer at #HUAWEI since March-2015 (#opentowork https://www.linkedin.com/in/-rw-r--r--) ʷⁱˡˡⁱⁿᵍ ᵗᵒ ˢᵉᵉ ʸᵒᵘ ⁱⁿ ᵃ ᵐⁱʳʳᵒʳ ᵐᵃᵈᵉ ᵒᶠ ᵐʸ ᵉʸᵉˢ # touch 'you ◔◡◔'
Updated on September 18, 2022Comments
-
αғsнιη over 1 year
I want to insert a new line in two lines before the last line. So if my original file is:
1 2 3 4 5
The result should be
1 2 3 New line 4 5
-
don_crissti almost 6 yearsThis will eat up any trailing blank lines in the input file.
-
don_crissti almost 6 yearsI suspect this will get really slow with a huge input file and a large no. of lines that follow the insertion... Also, just like Rakesh's solution, this requires sanitizing
NEW_LINE
before using it. -
don_crissti almost 6 yearsThis is the best solution so far but keep in mind that it has its limitations too (dealing with huge files or inserting lines that consist of a single dot).
-
Sparhawk almost 6 years@don_crissti Why do the trailing blank lines get eaten? The command within
$(...)
works fine by itself, so is it the assignment? -
don_crissti almost 6 years
-
saiyan boy sunny almost 6 yearsI have updated answer, now I am using redirection instead of command substitution and off-course it is preserving trailing blank lines
-
clay about 5 yearssimple and easy to understand