-8

I see there are discussions about removing trailing newlines.

How can I delete a newline if it is the last character in a file?

But I don't find a discusion about removing starting newlines. Could anybody let me know what is the best way to delete starting newlines (one liner preferred)? Thanks.

user1424739
  • 11,937
  • 17
  • 63
  • 152

5 Answers5

2

The equivalent-opposite Perl code to chomp is s/^\n//. Instead of doing it on the last line (eof), do it on the first line. Even though it will only be an empty line, removing the newline will mean that line will print nothing in the output.

perl -pe 's/^\n// if $. == 1' filename >filename2

or in place:

perl -pi -e 's/^\n// if $. == 1' filename

Since starting newlines are by definition empty lines, you can also just skip printing them by using -n instead of -p (same behavior but without printing, so you can determine which lines to print).

perl -ni -e 'print unless $. == 1 and m/^\n/' filename

If you want to remove potentially multiple starting newlines, you could take another approach; advance the handle yourself in the beginning until you receive a non-empty line.

perl -pi -e 'if ($. == 1) { $_ = <> while m/^\n/ }' filename

It's all much easier if you don't mind reading the entire file into memory at once rather than line by line:

perl -0777 -pi -e 's/^\n+//' filename

To avoid doing any excess work editing the file unless it starts with newline characters, you could condition the edit by prefixing it with another command (reads first line of the file and causes a non-zero exit status if it doesn't start with a newline):

perl -e 'exit 1 unless <> =~ m/^\n/' filename && perl ...
Grinnz
  • 9,093
  • 11
  • 18
  • Instead of substituting, just skip the line if it's just a newline. – Barmar Jan 17 '20 at 22:28
  • But I guess that would require using something other than the simple `perl -pie` loop. – Barmar Jan 17 '20 at 22:29
  • @Barmar Yes, you can't skip lines in `-p` as `$_` is always printed. But you can take that approach with `-n` - will add to the answer. – Grinnz Jan 17 '20 at 22:30
  • 1
    Also, the question says starting newlines -- plural. I asked for clarification, though. – Barmar Jan 17 '20 at 22:32
  • I don't quite following this `perl -pi -e 'if ($. == 1) { $_ = <> while m/^\n/ }' filename`. Could you please explain how it works? Thanks. – user1424739 Jan 18 '20 at 00:11
  • @user1424739 Only on the first line, when `$.` (current line number) will be 1, it will call `<>` again (this is done implicitly by `-p` or `-n` normally) until the current line is more than just a newline. `<>` is [readline](https://perldoc.pl/functions/readline) and will read the next line from `*ARGV` which will be the file passed on the command line. – Grinnz Jan 18 '20 at 00:21
  • Of all the inplace solutions here, I'd make sure it terminates immediately when the input contains no starting newline. This is critical for large input files. Do the solutions terminate immediate once it checks that there is not starting newlines? – user1424739 Jan 18 '20 at 00:31
  • @user1424739 Terminating immediately would mean the rest of the file would be omitted from the output. All of these solutions pass through the rest of the file unchanged. – Grinnz Jan 18 '20 at 00:49
  • @user1424739 It's important to remember that you can't actually edit files in place except for appending or byte-for-byte with a hex editor - "in place editing" in text is really just creating a whole new slightly different text file, and then copying it over the original. – Grinnz Jan 18 '20 at 00:55
  • @user1424739 For a solution that decides whether to edit the file first, it is probably better to step out of oneliner territory and use something like [Path::Tiny](https://metacpan.org/pod/Path::Tiny). – Grinnz Jan 18 '20 at 00:57
  • Or make it a two command process, check for starting newlines and then edit. – Grinnz Jan 18 '20 at 01:11
1

In Python, start reading the file without writing in a loop until you get a non-empty line.

outdata = ""
with open(filename) as infile:
    while True:
        line = infile.readline()
        if line != "\n":
            break
    if line:
        outdata = line # save first non-empty line
    outdata += infile.read() # save the rest of the file
with open(filename, "w") as outfile:
    outfile.write(outdata)
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

Simple filter to skip leading empty lines

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my $begin = 1;

while( <> ) {
        next if /^$/ and $begin;
        $begin = 0;
        say;
}

One liner version perl -0777 -pe 's/^\n+//' filename

Polar Bear
  • 6,762
  • 1
  • 5
  • 12
0

This is what I came up with, I'm sure it can still be improved a bit.

with open('../resources/temp_in.txt', 'r+') as file:
    overwrite = False
    for line in file:
        if line:
            overwrite = True
            first_line = line
            break
    if overwrite:
        contents = first_line + file.read()
        file.seek(0)
        file.write(contents)
        file.truncate()

Here is an alternative solution, which opens the file twice.

with open('../resources/temp_in.txt') as file:
    for line in file:
        if line.strip():
            contents = line + file.read()
            break
    else:
        contents = ''

with open('../resources/temp_in.txt', 'w') as file:
    file.write(contents)
AMC
  • 2,642
  • 7
  • 13
  • 35
  • When is it better to use seek? When is it better to just close the file and reopen it? – user1424739 Jan 18 '20 at 02:30
  • @user1424739 _When is it better to use seek?_ As opposed to what? _When is it better to just close the file and reopen it?_ That depends, how does closing and reopening fit into the rest of the potential solution? – AMC Jan 18 '20 at 02:30
  • The solution could be open the file, read the content into a variable, close the file, strip the leading newlines in the variable, open the file again, save the content of the variable into the file and close it. How is this different from your current solution performance wise. In other words, it is faster to seek or just close the file and reopen it? – user1424739 Jan 18 '20 at 02:35
  • @user1424739 Hmm, good question I guess since I’m reading/writing practically the entire file regardless, it shouldn’t make that much of a difference. I’ll whip up a quick solution. – AMC Jan 18 '20 at 02:38
  • @user1424739 See my edit. Do you have any test data, to ensure it works perfectly? – AMC Jan 18 '20 at 02:45
0

Set a flag when you find a line that's not just a newline and print when that flag is set:

awk '/./{f=1}f' file

e.g.:

$ printf '\n\n\nfoo\nbar\n'



foo
bar

$ printf '\n\n\nfoo\nbar\n' | awk '/./{f=1}f'
foo
bar
Ed Morton
  • 188,023
  • 17
  • 78
  • 185