Skip to content

Instantly share code, notes, and snippets.

@dabrahams
Last active September 5, 2024 19:30
Show Gist options
  • Save dabrahams/14fedc316441c350b382528ea64bc09c to your computer and use it in GitHub Desktop.
Save dabrahams/14fedc316441c350b382528ea64bc09c to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import os
import sys
import subprocess
if len(sys.argv) > 1:
files = []
for arg in sys.argv[1:]:
if os.path.exists(arg):
p = os.path.abspath(arg).replace('\\', '\\\\').replace('"', '\\"')
files.append('the POSIX file "' + p + '"')
else:
sys.stderr.write(
"%s: %s: No such file or directory\n" % (sys.argv[0], arg))
if len(files) > 0:
cmd = ['osascript', '-e',
'tell app "Finder" to move {' + ', '.join(files) + '} to trash']
r = subprocess.call(cmd, stdout=open(os.devnull, 'w'))
sys.exit(r if len(files) == len(sys.argv[1:]) else 1)
else:
sys.stderr.write(
'usage: %s file(s)\n'
' move file(s) to Trash\n' % os.path.basename(sys.argv[0]))
sys.exit(64) # matches what rm does on my system
@charpov
Copy link

charpov commented Feb 2, 2024

Here's a slight modification to handle large (ridiculous?) numbers of files, 1024 files at a time:

#!/usr/bin/env python
import os
import sys
import subprocess

MAX_FILES = 1024 # more files than that use several invocations of osascript

if len(sys.argv) > 1:
    files = []
    for arg in sys.argv[1:]:
        if os.path.exists(arg):
            p = os.path.abspath(arg).replace('\\', '\\\\').replace('"', '\\"')
            files.append('the POSIX file "' + p + '"')
        else:
            sys.stderr.write(
                "%s: %s: No such file or directory\n" % (sys.argv[0], arg))
    if len(files) > 0:
        for start in range(0, len(files), MAX_FILES):
            cmd = ['osascript', '-e',
               'tell app "Finder" to move {' + ', '.join(files[start:start + MAX_FILES]) + '} to trash']
            r = subprocess.call(cmd, stdout=open(os.devnull, 'w'))
            if r != 0:
                sys.exit(r)
        sys.exit(0 if len(files) == len(sys.argv[1:]) else 1)
else:
    sys.stderr.write(
        'usage: %s file(s)\n'
        '       move file(s) to Trash\n' % os.path.basename(sys.argv[0]))
    sys.exit(64) # matches what rm does on my system

@seamusdemora
Copy link

Wow... that's a lot of files for the trash.

P.S. love that... photo-caricature ? :)

@charpov
Copy link

charpov commented Feb 4, 2024

I've been known to combine trash with find, so 1000 files could happen, but I agree it's going to be rare...

This is the version I ended up using (I modernized Python a bit, reduced array copying, cleaned up the exit codes, and removed the help because I start the python script from my more general trash shell script only when I detect a MacOS system):

#!/usr/bin/env python3

# This is a script from Dave Abrahams, with minor edits
# See https://gist.github.com/dabrahams/14fedc316441c350b382528ea64bc09c.

import os
import sys
import subprocess

BATCH = 1024  # more files than that use several invocations of osascript
verbose = True

args = sys.argv[1:]
if args:
    if args[0] == '-q':
        verbose = False
        args.pop(0)
    files = []
    for arg in args:
        if os.path.exists(arg):
            if verbose:
                print(f"trashing {arg}")
            p = os.path.abspath(arg).replace('\\', '\\\\').replace('"', '\\"')
            files.append(f'the POSIX file "{p}"')
        else:
            print(f"{arg}: no such file or directory", file=sys.stderr)
    for start in range(0, len(files), BATCH):
        cmd = ['osascript', '-e',
               f'tell app "Finder" to move {{{", ".join(files[start:start + BATCH])}}} to trash']
        r = subprocess.call(cmd, stdout=open(os.devnull, 'w'))
        if r != 0:
            sys.exit(r)
    if len(files) != len(args):
        sys.exit(1)

@charpov
Copy link

charpov commented Sep 5, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment