File: android-deltas-sync/_etc/find-all-symlinks.py (original) (raw)
#!/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')