2

I want to create empty file using Python script in Unix environment. Could see different ways mentioned of achieving the same. What are the benefits/pitfalls of one over the other.

os.system('touch abc')

open('abc','a').close()

open('abc','a')

subprocess.call(['touch','abc'])
garg10may
  • 5,794
  • 11
  • 50
  • 91

4 Answers4

6

Well, for a start, the ones that rely on touch are not portable. They won't work under standard Windows, for example, without the installation of CygWin, GNUWin32, or some other package providing a touch utility..

They also involve the creation of a separate process for doing the work, something that's totally unnecessary in this case.

Of the four, I would probably use open('abc','a').close() if the intent is to try and just create the file if it doesn't exist. In my opinion, that makes the intent clear.

But, if you're trying to create an empty file, I'd probably be using the w write mode rather than the a append mode.

In addition, you probably also want to catch the exception if, for example, you cannot actually create the file.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
6

TLDR: use

open('abc','a').close()

(or 'w' instead of 'a' if the intent is to truncate the file if it already exists).

Invoking a separate process to do something Python can do itself is wasteful, and non-portable to platforms where the external command is not available. (Additionally, os.system uses two processes -- one more for a shell to parse the command line -- and is being deprecated in favor of subprocess.)

Not closing an open filehandle when you're done with it is bad practice, and could cause resource depletion in a larger program (you run out of filehandles if you open more and more files and never close them).

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 2
    `open()` may block if the name corresponds to a named pipe. You could [use `os.open()` to open it in non-blocking mode](http://stackoverflow.com/a/28084217/4279). – jfs Jan 22 '15 at 08:34
2

To create an empty file on Unix in Python:

import os

try:
    os.close(os.open('abc', os.O_WRONLY | os.O_CREAT | os.O_EXCL | 
                     getattr(os, "O_CLOEXEC", 0) |
                     os.O_NONBLOCK | os.O_NOCTTY))
except OSError:
    pass # decide what to consider an error in your case and reraise
    # 1. is it an error if 'abc' entry already exists?
    # 2. is it an error if 'abc' is a directory or a symlink to a directory?
    # 3. is it an error if 'abc' is a named pipe?
    # 4. it is probably an error if the parent directory is not writable 
    #    or the filesystem is read-only (can't create a file)

Or more portable variant:

try:
    open('abc', 'ab', 0).close()
except OSError:
    pass # see the comment above

Without the explicit .close() call, non-reference-counting Python implementations such as Pypy, Jython may delay closing the file until garbage collection is run (it may exhaust available file descriptors for your process).

The latter example may stuck on FIFO and follows symlinks. On my system, it is equivalent to:

from os import *
open("abc", O_WRONLY|O_CREAT|O_APPEND|O_CLOEXEC, 0666)

In addition, touch command updates the access and modification times of existing files to the current time.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Out of context, ignoring the error is dubious advice. The caller should be notified somehow if the requested operation fails. – tripleee Jan 22 '15 at 08:35
  • @tripleee: what is an error in this case? `touch dir` has zero exit status but it reports permission errors. The code could be change to suppress only specific class of errors. Each application may choose what is appropriate. – jfs Jan 22 '15 at 08:49
0

In more recent Python 3 variants, we have Path.touch() from pathlib. This will create an empty file if it doesn't exist, and update the mtime if it does, in the same way as your example os.system('touch abc'), but it's much more portable:

from pathlib import Path

abc = Path('abc')
abc.touch()
SpinUp __ A Davis
  • 5,016
  • 1
  • 30
  • 25