rm all files under a directory using python subprocess.call

rodneyxr picture rodneyxr · Aug 13, 2015 · Viewed 8.1k times · Source

I'm writing a script that will move files into a .trash directory in a user's home folder. I want to add the ability to empty the trash directory by calling rm -rf /home/user/.trash/* using python's subprocess.call()

~$ touch file1
~$ trash file1
['mv', 'file1', '/home/rodney/.trash/']
~$ ls .trash
file1
~$ trash --empty
['rm', '-rf', '/home/rodney/.trash/*']
~$ ls .trash
file1

As you can see the rm command did not remove the contents of the trash. However if I execute the command directly on the command line it works.

~$ rm -rf /home/rodney/.trash/*
~$ ls .trash
~$ 

The output is from the following code

print(cmd)
subprocess.call(cmd)

What is weird about this is if I exclude the * from the last argument in the cmd list then the subprocess call works but also removes the entire .trash directory. I do not want to delete the .trash directory; only everything under it.

To sum up the question

This works

import subprocess
subprocess.call(['rm', '-rf', '/home/rodney/.trash/'])

This does not

import subprocess
subprocess.call(['rm', '-rf', '/home/rodney/.trash/*'])

Why?

Answer

Jonathon Reinhart picture Jonathon Reinhart · Aug 13, 2015

Don't shell out.

This uses glob.glob() to identify the files to be removed, and shutil.rmtree() to remove subdirectories.

#!/usr/bin/env python
import os, os.path
import glob
import shutil

def remove_thing(path):
    if os.path.isdir(path):
        shutil.rmtree(path)
    else:
        os.remove(path)

def empty_directory(path):
    for i in glob.glob(os.path.join(path, '*')):
        remove_thing(i)

empty_directory('trash')

Example:

$ tree trash/
trash/
├── aaa
├── bbb
├── ccc
├── ddd
└── sub
    ├── iii
    └── jjj

1 directory, 6 files

$ ./go.py 

$ tree trash/
trash/

0 directories, 0 files