Search code examples
pythonpython-3.xsubprocesspython-3.4rm

rm all files under a directory using python subprocess.call


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?


Solution

  • 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