Removing a newline character at the end of a file
Asked Answered
M

7

62

To remove all newlines you could, say:

tr -d '\n' < days.txt
cat days.txt | tr -d '\n'

but how would you use tr to remove just the newline at the end/bottom of a text file?

I'm not sure to specify just the last one.

Mucor answered 3/5, 2013 at 18:12 Comment(1)
possible duplicate of How can I delete a newline if it is the last character in a file?Manque
F
32

Take advantage of the fact that a) the newline character is at the end of the file and b) the character is 1 byte large: use the truncate command to shrink the file by one byte:

# a file with the word "test" in it, with a newline at the end (5 characters total)
$ cat foo 
test

# a hex dump of foo shows the '\n' at the end (0a)
$ xxd -p foo
746573740a

# and `stat` tells us the size of the file: 5 bytes (one for each character)
$ stat -c '%s' foo
5

# so we can use `truncate` to set the file size to 4 bytes instead
$ truncate -s 4 foo

# which will remove the newline at the end
$ xxd -p foo
74657374
$ cat foo
test$ 

You can also roll the sizing and math into a one line command:

truncate -s $(($(stat -c '%s' foo)-1)) foo
Freeboard answered 3/5, 2013 at 19:2 Comment(0)
A
100

A simpler solution than the accepted one:

truncate -s -1 <<file>>

From the truncate man page (man truncate):

-s, --size=SIZE
    set or adjust the file size by SIZE
SIZE may also be prefixed by one of the following modifying characters:
    '+' extend by, '-' reduce by, '<' at most, '>' at least, '/' round down
    to multiple of, '%' round up to multiple of.
Amigo answered 3/12, 2014 at 14:29 Comment(1)
Thank you for providing a simple solution. A lot of these “Unix” approaches that rely on some side-effect or quirk of filtering or processing things in sed/awk/perl are not really simple.Voroshilov
F
32

Take advantage of the fact that a) the newline character is at the end of the file and b) the character is 1 byte large: use the truncate command to shrink the file by one byte:

# a file with the word "test" in it, with a newline at the end (5 characters total)
$ cat foo 
test

# a hex dump of foo shows the '\n' at the end (0a)
$ xxd -p foo
746573740a

# and `stat` tells us the size of the file: 5 bytes (one for each character)
$ stat -c '%s' foo
5

# so we can use `truncate` to set the file size to 4 bytes instead
$ truncate -s 4 foo

# which will remove the newline at the end
$ xxd -p foo
74657374
$ cat foo
test$ 

You can also roll the sizing and math into a one line command:

truncate -s $(($(stat -c '%s' foo)-1)) foo
Freeboard answered 3/5, 2013 at 19:2 Comment(0)
P
31

If you are sure the last character is a new-line, it is very simple:

head -c -1 days.txt

head -c -N means everything except for the last N bytes

If you want to modify the file in-place:

truncate -s -1 days.txt

It will remove the last byte of the file, regardless of what it is.

Peadar answered 5/5, 2013 at 18:3 Comment(5)
got head: illegal byte count -- -1 on OS X Yosemite 10.10.5 :(Annoyance
same on MacOS High Sierra 10.13. illegal byte countGazpacho
For MacOS you need to brew install coreutils and use ghead.Armoured
This solution does not do it in-place.Agreeable
@ks1322: I just added a solution for that problem too.Afterburner
E
18

I think your best bet is Perl:

perl -0pe 's/\n\Z//' days.txt

The -p causes perl to read the file, run the supplied program (the argument to -e) on it, and print the result back out. Normally it would do that in a loop, running the program once per line; -0 causes it to instead run the code just once, with the entire file as one big screen.

The regular expression \n\Z matches a newline, but only if it's the last character in a string. And s/\n\Z// says to replace such a newline with nothing at all, deleting it.

The above command outputs the new version of the file, but you can instead modify the existing one by adding the -i ("in-place") option, optionally with a suffix that will be used to name a backup copy of the file before modifying it:

 perl -i.bak -0pe 's/\n\Z//' days.txt

This solution is safe in that if the last character is not a newline, it won't be touched. The other solutions which simply remove the last byte no matter what may corrupt such a file.

Enabling answered 3/5, 2013 at 18:19 Comment(1)
This works on macOS as well, unless truncate or head -c -1.Zinkenite
D
9

Try this command: sed '$ { /^$/ d}' days.txt

You can read it as: "check if last line is an empty line. if so delete this line". I tested with both cases: first with a file having a new line at the end and an other time with a file ending with something else.

Demodulate answered 4/5, 2013 at 7:12 Comment(1)
Even better with sed's in-place mode: sed -i '$ { /^$/ d}' days.txtPulsometer
A
8

Another Sed solution:

sed -z s/.$// days.txt

The -z option is to interpret the file as a single long string (newlines are embedded as \n), then s matches the single character . before the end of line (= end of file) $, and changes it into nothing. No need for quoting the command.

If you are not sure the last character is a newline, then you do either of these:

sed -z s/\\n$// days.txt
sed -z 's/\n$//' days.txt
Arturo answered 7/9, 2020 at 12:11 Comment(3)
This seems to be the right solution to me. (Lynch's solution only works for an empty line, the other solutions need to know there's a newline). But it doesn't work for some reason. Newline is still there in my case.Disjoin
You have to > days2.txt or to add the -i option of your seed flavor supports it.Arturo
"If you are not sure the last character is a newline..." sed -z 's/\n$//' days.txt Thanks @Enlico!Wrapping
F
3

If you want to remove the newline at the end of the file, you can use:

truncate -s -1 file_name.txt

The change will be saved in the file.

Foehn answered 24/7, 2022 at 10:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.