Once in a while I can’t empty the trash because one file is in use. It doesn’t happen very often but once in a while. You then get such an error message:
When you then press continue all other files in the trash but this one file are removed. Mac OS X won’t let you delete this file as long as it’s in use. Unfortunately, it won’t tell you which program is using it.
There is an effective brute force method to solve the problem and a more elegant one. First the brute force method: You can delete the files in the trash from a terminal window. The trash is located in a .Trash folder in your user directory. You can get there with:
cd ~/.Trash
You will the file in there. You can just remove everything from the trash using:
rm -rf *
But you have to be careful. This command will delete everything recursively starting from the directory where you are. If you misspelled the directory and are not actually in the trash but in your user directory, it will delete many things you did not intend to delete. A solution for this problem is to combine the two commands above and only execute the second one if the first one was successfull. This is done combining them with &&:
cd ~/.Trash && rm -rf *
Of course deleting a file which is in use by a program might lead this problem to have an unpredictable behavior. So now to the more elegant solution. Instead of just deleting everything from the command line, we’ll first try to figure out which program is actually using the file. This is done using the lsof command:
Lsof lists on its standard output file information about files opened by processes.
It will basically return a list of all files (among other things) are opened by which process. We can then redirect the output to grep to filter by the file name which is in use (in my case some_file.mp4):
$ lsof | grep some_file.mp4 QuickTime 81275 henribenoit 5r REG 1,2 192918592 32326555 /Users/henribenoit/.Trash/some_file.mp4
So now, you know it’s Quicktime. If the process name displayed in there is not so clear, you can get a full command line for the process which is preventing the file from being deleted. If you want to kill the process you can just use the commands at the end of this post. But I’d actually like to find out about the program and close it properly. This can be done by using the ps command:
$ ps 81275 PID TT STAT TIME COMMAND 81275 ?? S 0:58.83 /Applications/QuickTime Player.app/Contents/MacOS/QuickTime Player -psn_0_17662167
So we now we have the full command line (in this case it wasn’t required but does help in some cases). You can also combine the commands above into one with the same results:
$ ps `lsof | grep some_file.mp4 | awk ' { print $2; } '` PID TT STAT TIME COMMAND 81275 ?? S 0:58.83 /Applications/QuickTime Player.app/Contents/MacOS/QuickTime Player -psn_0_17662167
If you ever get a command name for which you cannot find the corresponding program, you have two options: search for the parent process or just kill the process (note that wild process killing doesn’t really improve the stability of the system).
First we’ll lookup the parent process. This can be done using ps but we need to add the -f option to see the process ID of the parent process:
$ ps -f `lsof | grep some_file.mp4 | awk ' { print $2; } '` UID PID PPID C STIME TTY TIME CMD 501 81275 135 0 8:52PM ?? 0:58.84 /Applications/QuickTime Player.app/Contents/MacOS/QuickTime Player -psn_0_17662167
The column PPID shows the parent process ID. Now we can use ps once again to get info about the process 135:
$ ps 135 PID TT STAT TIME COMMAND 135 ?? Ss 0:16.98 /sbin/launchd
Of course in my case it’s not very interesting since the blocking process is an application so the parent is launchd. But in other cases, it might be useful. You can recurse until you find an applicaiton you acn close. If none of this work, you need to either force the deletion of the files as shown above or you need to kill the process:
$ kill 81275 && ps 81375 PID TT STAT TIME COMMAND
Now the blocking process is gone and you can fully empty the trash can. If the process doesn’t exit on kill, you should add the -9 option to force kill the process:
$ kill -9 81275 && ps 81375