Company logo with the letters 'NotTooBad Software' TextSmith Blog

Move files to the trash with a Swift script

SwiftShell  

Swift 3

I really don’t like using the ‘rm’ shell command – one misplaced character and you can do some serious damage. But when working in the Finder I don’t think twice about deleting files, because I know I can always get them back from the trash. So here is a Swift shell script which does exactly that – it moves files to the trash instead of deleting them permanently.

The syntax is very simple – all parameters refer to file system items which should be moved to the trash:

trash file.txt a_folder
trash *.m *.h

The code (gist)

import SwiftShell

import Dispatch
import Cocoa

extension Sequence where Iterator.Element: Hashable {
    /// Returns an array containing each element in `self` only once, in the same order. Complexity: O(n)
    func removeDuplicates () -> [Iterator.Element] {
        var alreadyhere = Set<Iterator.Element>(minimumCapacity: underestimatedCount)
        return filter { x in alreadyhere.contains(x) ? false : { alreadyhere.insert(x); return true }() }
    }
}

DispatchQueue.main.async {
    let filesToTrash = main.arguments.removeDuplicates().map(URL.init(fileURLWithPath:))

    NSWorkspace.shared().recycle(filesToTrash) { trashedFiles, error in
        guard let error = error else { exit(0) }

        main.stderror.print("Files that could not be trashed:")
        for file in filesToTrash where trashedFiles[file] == nil {
            main.stderror.print(file.relativePath)
        }
        main.stderror.print()
        exit(error)
    }
}

RunLoop.current.run()

The script is based on this gist but updated for Swift 3 and uses SwiftShell for output to standard error. The actual work of moving the files to the trash is performed by NSWorkspace.sharedWorkspace().recycleURLs. Since this is an asynchronous method we need to launch it in a Grand Central Dispatch block and then have the run loop wait until the method is finished so we get a chance to print any errors before the script exits.

We call removeDuplicates on the arguments list to avoid an error message if we try to trash the same file item twice. Then in the callback from recycleURLs we check for errors – if there are any we print the names of the file items that could not be trashed, and then the error.

Updates

Suggest changes to post.

Comments

Want to hear about new posts?