113

Suppose I have a file called file:

$ cat file
Hello
Welcome to
Unix

I want to add and Linux at the end of the last line of the file. If I do echo " and Linux" >> file will be added to a new line. But I want last line as Unix and Linux

So, in order to work around this, I want to remove newline character at the end of file. Therefore, how do I remove the newline character at the end of file in order to add text to that line?

Kusalananda
  • 333,661
Pandya
  • 24,618

5 Answers5

107

If all you want to do is add text to the last line, it's very easy with sed. Replace $ (pattern matching at the end of the line) by the text you want to add, only on lines in the range $ (which means the last line).

sed '$ s/$/ and Linux/' <file >file.new &&
mv file.new file

which on Linux can be shortened to

sed -i '$ s/$/ and Linux/' file

If you want to remove the last byte in a file, Linux (more precisely GNU coreutils) offers the truncate command, which makes this very easy.

truncate -s -1 file

A POSIX way to do it is with dd. First determine the file length, then truncate it to one byte less.

length=$(wc -c <file)
dd if=/dev/null of=file obs="$((length-1))" seek=1

Note that both of these unconditionally truncate the last byte of the file. You may want to check that it's a newline first:

length=$(wc -c <file)
if [ "$length" -ne 0 ] && [ -z "$(tail -c -1 <file)" ]; then
  # The file ends with a newline or null
  dd if=/dev/null of=file obs="$((length-1))" seek=1
fi
65

You can achieve this with perl as:

perl -pi -e 'chomp if eof' myfile

Compared to truncate or dd this not gonna leave you with a broken file if myfile had actually no trailing newlines.

(the answer is constructed from the comment, and based on this answer)

Hi-Angel
  • 5,122
  • Thank-you! This conditional method of removing is trailing newline is perfect. – xer0x Nov 04 '19 at 18:56
  • Best answer. Too bad for everyone that you were late to the party. – webb Dec 12 '20 at 00:14
  • 1
    best answer! Also to make this easy to use, I just defined a little function like this: function chomp() { perl -p -e 'chomp if eof' }. Now I can strip a new line with a pipe like this: cat /tmp/file | chomp. – Chris Jun 20 '21 at 23:27
59

Though, you can remove newline character from all lines by using tr -d '\n':

$ echo -e "Hello"
Hello
$ echo -e "Hello" | tr -d '\n'
Hello$

You can remove the newline character at the end of file using following easy way:

  1. head -c -1 file

From man head:

    -c, --bytes=[-]K
              print the first K bytes of each file; with the leading '-',
              print all but the last K bytes of each file
  1. truncate -s -1 file

from man truncate:

    -s, --size=SIZE
              set or adjust the file size by SIZE
    SIZE is an integer and optional unit (example: 10M is 10*1024*1024).
    Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB, ... (powers of 1000).

    SIZE  may  also be prefixed by one of the following modifying characters: 
    '+' extend by, '-' reduce by, '' at least, '/' round down to multiple of, '%' round up to multiple of.
SebMa
  • 2,149
Pandya
  • 24,618
  • is head -c -1 file | tee file safe? Wouldn't tee truncate the file before starting? – iruvar Jan 11 '16 at 17:14
  • 1
    @1_CR Indeed. The two sides of the pipe start in parallel, it's a matter of who wins the race. Since tee only has to open the file, whereas head has to read and write its contents, tee will in practice win the race except sometimes for very small files. – Gilles 'SO- stop being evil' Jan 11 '16 at 22:46
  • 7
    This doesn't remove last newline, it remove all newlines. IMO quite a big difference. – Hi-Angel May 27 '19 at 13:16
  • 1
    Solution 2 should be the accepted answer. If your file is huge you really do not want to read the full file. – Ole Tange Dec 17 '20 at 19:28
5

Here's one way with sed -- on the last ($) line of the file, search and replace anything and everything (.*) with "whatever you matched" followed by " and Linux":

sed '$s/\(.*\)/\1 and Linux/' file

An even simpler solution, courtesy of Isaac, is:

sed '$s/$/ and Linux/' file

This replaces the (symbolic) end-of-line with the given text.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
2
perl -0pi -e "s/\R\z//g" file

Works for "\r" (MAC), "\r\n" (Windows) and "\n" (Linux). For repeated newlines (any tipe) at end of file you can do:

perl -0pi -e "s/\R*\z//g" file
Mario Palumbo
  • 233
  • 1
  • 14