1

I want to append / concatenate a text in one line before the last line. So if my original file is:

1 sometext
2 sometext
3 sometext
4 sometext
5 sometext

my new file is

1 sometext
2 sometext
3 sometext
4 sometext newtext
5 sometext

I know already about solution on how to insert newlines but this is a slightly different problem as I do not want a new line inserted and want concatenation of text instead.

pyoupyou
  • 21
  • 3

6 Answers6

3

Reverse the file line-by-line, add the text to the second line, and reverse the file again:

tac file | sed '2s/$/ newtext/' | tac
Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
3

vim understands an address like $-1:

ex -sc '$-1s/$/ newtext/' +wq file

ex same as vim -e

nezabudka
  • 2,376
  • 5
  • 15
2
$ awk 'NR>1{printf "%s%s", ors, prev; ors=ORS} {prev=$0} END{print OFS "newtext" ORS prev}' file
1 sometext
2 sometext
3 sometext
4 sometext newtext
5 sometext
Ed Morton
  • 28,789
  • 5
  • 20
  • 47
1
line=$(awk 'END{print NR-1}' filename)
awk -v line="$line" 'NR==line{$0=$0" newtext"}1' filename

output

1 sometext
2 sometext
3 sometext
4 sometext newtext
5 sometext
Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
Praveen Kumar BS
  • 5,139
  • 2
  • 9
  • 14
0

Getting the address via counting lines and arithmetic:

sed "$(wc -l infile | awk '{print $1-1}')s/$/ newtext/" infile
FelixJN
  • 12,616
  • 2
  • 27
  • 48
0

Using Raku (formerly known as Perl_6)

~$ raku -e 'my @txt=lines; my [email protected]; for @txt.kv -> $k,$v {$k == ($kmax-2) ?? put( $v, " newtext") !! put($v) };' sometext.txt

OR

~$ raku -e '.put for "sometext.txt".IO.lines[0..*-3]; put($_, " newtext") for "sometext.txt".IO.lines[*-2]; .put for "sometext.txt".IO.lines[*-1];'

Sample Input:

1 sometext
2 sometext
3 sometext
4 sometext
5 sometext

Sample Output (for both code examples):

1 sometext
2 sometext
3 sometext
4 sometext newtext
5 sometext

The above two Raku code examples represent a starting point. I'm certain these can be improved. The first example using kv key-value numbering is adapted (generally) from this SO answer, while the second example is adapted (generally) from this Perl(5)doc FAQ.

Example 1: Briefly, lines are read in and stored in the @txt array. The number of lines is obtained using elems and assigned to the $kmax (key-maximum) scalar. The @txt array is converted to kv key-value and read into a for loop, which implements a condition ?? $true !! $false ternary conditional operator. See this link for info on the Raku ternary. Text is appended to the appropriate $k == ($kmax-2) (penultimate) line using said ternary operator.

Example 2: This is really adapted straight from the Perl5 code. The difference is that Raku's lines routine handles opening/closing filehandles, and is lazy as well. The Raku code simply implements three succesive put ("print-using-\n-terminator") statements, however a difference (compared to Perl5) is that file-lines are read in as IO objects, and not off of the (presumably bash) command line.

Example 2 (cont'd): The second (middle) statement appends " newtext" to the $_ topic variable (containing line-text), while the first and third statements prints the before/after text verbatim. Of course, output can be redirected to a file instead of outputting to the terminal, e.g. by appending > new_sometext.txt to the end of the Example 2 code above.

Looking at the the Perl(5)doc FAQ, we see a number of modules used to solve this problem in Perl5. Raku (née Perl6) has cognate modules...meaning more concise/efficient solutions may be available in Raku using modules.

Finally, if you run into problems fitting the file into memory, and/or you prefer getting the # of lines separately, you can do that via the Raku one-liner:

~$ raku -ne 'state $i; $i++; END put $i-1;' sometext.txt
4

Then simply run the code below, using the computed (penultimate) line-number 3:

~$ raku -ne 'if $++ == 3 { say($_, " newtext") } else { say($_) };' sometext.txt
1 sometext
2 sometext
3 sometext
4 sometext newtext
5 sometext
jubilatious1
  • 2,385
  • 8
  • 16