File: android-deltas-sync/_etc/find-all-symlinks.py
#!/usr/bin/env python3 """ ======================================================================================= find-all-symlinks.py: an Android Deltas Sync utility Runs on: any Python 3.X, and any host platform License: provided freely, but with no warranties of any kind Attrib: © M. Lutz (https://learning-python.com), Oct-2022 Synopsis: Locate and report all symlinks in the folder tree whose pathname is passed in as a sole argument (or in '.' if no argument is passed). Though context dependent, symlinks may not survive trips to and from some platforms and filesystems (e.g., exFAT and Android). This script does not mod symlinks, but points them out as a portability caution. Run manually as needed before propagating content with main scripts, and see **CAUTION** in ../x-export-phone-part1-phone.py for more info. Coding: os.walk() does not step from a link into a folder when passed followlinks=False, which is its default. To make this a more explicit option here, we pass True, and trim the subfolders list. Even so, you generally don't want to follow symlinks to folders/dirs; they can exit the tree being scanned, visit folders more than once, and trigger loops. Example output: ~$ python3 $Code/find-all-symlinks.py ~/MY-STUFF/ Scanning /Users/me/MY-STUFF ... Visited 177249 files and 17690 folders in 2.09 seconds Total symlinks found: 161 Display links' paths (y=yes)? n Bye Alternatives: You can get the same results from a Unix find command, where available: ~$ find ~/Desktop -type l -print ...link paths here... ~$ find ~/Desktop -type l -print | wc -l 153 But Python code is more portable, customizable, and fun: ~$ python3 $Code/find-all-symlinks.py ~/Desktop Scanning /Users/me/Desktop ... Visited 105728 files and 12732 folders in 2.65 seconds Total symlinks found: 153 Display links' paths (y=yes)? y Paths of links found: ...link paths here... Bye ======================================================================================= """ # CODE import sys, os, time helpmsg = 'Usage: python3 find-all-symlinks.py [folderrootpath]' trimdlinks = True # true = do not follow links to folders trace = lambda *args: None # print = display folder links skipped # get arg if len(sys.argv) > 1 and sys.argv[1] in ('?', '-help', '--help'): print(helpmsg) sys.exit(1) elif len(sys.argv) < 2: root = os.path.abspath(os.getcwd()) else: root = os.path.abspath(sys.argv[1]) assert os.path.isdir(root), 'argument must be a folder path' if len(sys.argv) > 2: print('Extra arguments ignored') # walk folder tree start = time.perf_counter() print('Scanning', root, '...') linkpaths = [] numlinks = numfiles = numdirs = 0 walker = os.walk(root, followlinks=True) for (thisdir, subshere, fileshere) in walker: # for all folders in tree numdirs += len(subshere) # symlinks in subs/fileshere numfiles += len(fileshere) for name in subshere + fileshere: # for all subfolders and files path = os.path.join(thisdir, name) if os.path.islink(path): numlinks += 1 linkpaths.append(path) if trimdlinks and name in subshere: # skip links to dirs on walk subshere.remove(name) # else may exit tree, loop, etc trace(' Trimmed linked dir:', path) # okay to mod: + made a copy elapsed = time.perf_counter() - start print('\nVisited %d files and %d folders in %.2f seconds' % (numfiles, numdirs, elapsed)) print('Total symlinks found: %d' % numlinks) if numlinks > 0 and input('Display links\' paths (y=yes)? ').lower() in ['y', 'yes']: print('Paths of links found:') for path in sorted(linkpaths): print('', path) print('Bye\n')