6

I'm looking for one liner which will remove all the blank lines from a file in python. python equivalent for --> grep -v '^$' file_name > file_name

Mandar Pande
  • 12,250
  • 16
  • 45
  • 72

8 Answers8

10
lines = [i for i in open(file_path) if i[:-1]]

If writing to another file is a requirement, you can use file_object.writelines(lines) with opening file for writing.

utdemir
  • 26,532
  • 10
  • 62
  • 81
  • *In a one-liner*, how is `with` safer? – Mike DeSimone Jul 19 '11 at 11:34
  • Changing comprehension to a loop changes nothing, but changing `with` to an inline open() would be more error-prone I think. Why being in a one-liner changes something? – utdemir Jul 19 '11 at 11:43
  • IIRC, the whole point of `with` in the context of a file is to ensure the file gets closed. Since all files get closed on termination, the `with` makes no difference here. – Mike DeSimone Jul 19 '11 at 11:59
  • 1
    `bool(line.rsplit())` isn't equivalent to a negation of `^$` match. `bool(line[:-1])` is. – Dzinx Jul 19 '11 at 12:11
  • @DzinX, my mistake, should be i.rstrip(), but since empty list is false either, did work. Edit: Yes, I noticed it erases lines with whitespace too. But I don't really think that would be problem, but anyway changed answer. – utdemir Jul 19 '11 at 12:17
6

The following isn't a one-liner, but does the job and is easy to read:

for line in open(filename):
  line = line.rstrip()
  if line != '':
    print line

This prints the result to standard output. It is trivial to modify this code to print elsewhere.

If you insist, it is fairly easy to convert it to a one-liner:

''.join(l for l in open(filename) if l.rstrip())
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Not a one liner, and to quote the Python docs, "!= can also be written <>, but this is an obsolete usage kept for backwards compatibility only. New code should always use !=.". – agf Jul 19 '11 at 10:49
  • @agf: How do you guys manage to comment on old versions of the answer? Is this a replication issue of some sort? I've removed the `<>` quite some time before you posted the comment. – NPE Jul 19 '11 at 10:51
  • Beats me. Also, even `!=` is unnecessary in this case as an empty string evaluates to false, and why not use `with` if you're doing a multi-liner? – agf Jul 19 '11 at 10:54
2

A loopless one:

open('dst','w').write(re.sub('\n\s*\n+','\n', open('src').read()))
dugres
  • 12,613
  • 8
  • 46
  • 51
  • +1 Though I ended up using this for my needs: open('dst','w').write(re.sub('\n[\t\s]*\n+','\n', open('src').read())) Matching tabs and spaces in any combination, just in case. – leetNightshade Jan 24 '13 at 15:26
1

filter(bool, map(lambda x:x.rstrip(), open(filename)))

Daniel Kluev
  • 11,025
  • 2
  • 36
  • 36
  • 3
    You can use `str.rstrip` as a key instead of creating a lambda function. – utdemir Jul 19 '11 at 10:51
  • This is nice but it is not an equivalent because it doesn't close the file, doesn't preserve spaces in non-empty lines and doesn't write the output to a resulting file. – Mikhail Korobov Jul 19 '11 at 10:52
1

If you need a real one-liner:

python -c 'import sys; print "".join(l for l in sys.stdin.readlines() if l.strip()),'

which can be used in your shell as:

cat input.txt | python -c 'import sys; print "".join(l for l in sys.stdin.readlines() if l.strip()),' > output.txt
eumiro
  • 207,213
  • 34
  • 299
  • 261
1

If you want to process large files without worrying about out-of-memory errors, you should do it in a loop:

import sys

for line in sys.stdin:
    if line[:-1]:
        sys.stdout.write(line)

If must have a one-liner, here's the same code in one line:

for _ in (sys.stdout.write(line) for line in sys.stdin if line[:-1]): pass

EDITED to include agf's hint.

Dzinx
  • 55,586
  • 10
  • 60
  • 78
  • if you do `for Null in (sys.stdout.write(line) for line in sys.stdin if line.strip()): pass` you're not saving the `None`s (exept one, anyway) – agf Jul 19 '11 at 11:25
  • Thanks for the hint. I forgot that you don't have to put a newline after the colon. I modified my example. BTW `line.strip()` would skip non-empty lines with spaces only. – Dzinx Jul 19 '11 at 11:33
  • I know, but they'd fit my definition of 'empty'. – agf Jul 19 '11 at 11:34
  • "[...for...in...]" instead of "for _ in (...for...in...): pass" – dugres Jul 19 '11 at 16:51
  • @dugres: that would accumulate a potentially long list of Nones (see agf's first comment and edition history of my answer). – Dzinx Jul 21 '11 at 10:10
0
os.system("grep -v '^$' file_name > file_name")
Tugrul Ates
  • 9,451
  • 2
  • 33
  • 59
  • @Jakob I don't know if it's pointless. The OP does not explain why does he needs this one-liner. It looks like a good answer to me. It does not work on windows though. – Simon Bergot Jul 19 '11 at 11:47
  • Read the question python equivalent for --> `grep -v '^$' file_name > file_name` he doesn't want to execute grep otherwise he would just use the cmd line, os.system is the WORST way to execute shell commands and its not cross platorm – Jakob Bowyer Jul 19 '11 at 11:50
0

The fileinput module has the 'inplace' option for the express purpose of editing files in one step. While the file is being read, standard output is temporarily redirected to the input file.

Here's a one-liner that will do what you want (done in bash):

python -c $'import sys, re, fileinput\nfor line in fileinput.input("file_name", inplace=True): sys.stdout.write( re.sub(r"^\\n$", "", line) )'
Droj
  • 3,541
  • 3
  • 26
  • 19