23

I'm trying to build a function that will remove all the files that start with 'prepend' from the root of my project. Here's what I have so far

def cleanup(prepend):
    prepend = str(prepend)
    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
    end = "%s*" % prepend
    cmd = 'rm'
    args = "%s/%s" % (PROJECT_ROOT, end)
    print "full cmd = %s %s" %(cmd, args)
    try:
        p = Popen([cmd, args],  stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True).communicate()[0]
        print "p", p
    except Exception as e:
        print str(e)

I'm not having any luck -- it doesn't seem to be doing anything. Do you have any ideas what I might be doing wrong? Thank you!

brandizzi
  • 26,083
  • 8
  • 103
  • 158
mythander889
  • 915
  • 5
  • 16
  • 23
  • I think Levon's answer is the better approach; that said, if you want to see what this is doing, run this under `strace(1)` with `-f` command line option and you can see the exact `execve(2)` system call that is being made. – sarnold Jun 14 '12 at 02:17

3 Answers3

20

The problem is that you are passing two arguments to subprocess.Popen: rm and a path, such as /home/user/t* (if the prefix is t). Popen then will try to remove a file named exactly this way: t followed by an asterisk at the end.

If you want to use Popen with the wildcard, you should pass the shell parameter as True. In this case, however, the command should be a string, not a list of arguments:

Popen("%s %s" % (cmd, args), shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)

(Otherwise, the list of arguments will be given to the new shell, not to the command)

Another solution, safer and more efficient, is to use the glob module:

import glob
files = glob.glob(prepend+"*")
args = [cmd] + files
Popen(args,  stdin=PIPE, stdout=PIPE, stderr=PIPE)

However, I agree that Levon's solution is the saner one. In this case, glob is the answer too:

files = glob.glob(prepend+"*")
for file in files:
    os.remove(file)
brandizzi
  • 26,083
  • 8
  • 103
  • 158
18

Would you consider this approach using os.remove() to deleting files instead of rm:

import os
os.remove('Path/To/filename.ext')

Update (basically moving my comment from below into my answer):

As os.remove() can't handle wildcards on its own, using the glob module to help will yield a solution as repeated verbatim from this SO answer:

import glob
import os
for fl in glob.glob("E:\\test\\*.txt"):
    #Do what you want with the file
    os.remove(fl)
Community
  • 1
  • 1
Levon
  • 138,105
  • 33
  • 200
  • 191
  • Definitely! Can I use wildcards in the remove call? – mythander889 Jun 14 '12 at 02:22
  • 2
    `os.remove()` by itself can't handle wildcards, but this SO answer shows some code using `os.remove()` with the `glob` module to do just this: http://stackoverflow.com/a/5532521/1209279 .. there are other approaches also shown. – Levon Jun 14 '12 at 02:27
  • 1
    @mythander889 No -- wildcards are evaluated by the shell, and the best ways of doing this (from a security perspective) have no shell involved. `import glob, os; for filename in glob.glob('*.txt'): os.remove(filename)` – Charles Duffy Jun 14 '12 at 02:27
0

I would try something like this (which also works on Windows, though I'm guessing that's not a concern for you:

def cleanup(prepend):
    prepend = str(prepend)
    PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
    for file_to_delete in [file for file in os.listdir(PROJECT_ROOT) if file.startswith(prepend)]:
        os.remove(file_to_delete)
Jack Leow
  • 21,945
  • 4
  • 50
  • 55