Unlike Windows, Linux is case sensitive.  When you copy over files from a Windows machine and start working with a couple hundred of them, it can be infuriating that files are skipped during processing because the suffix was .JPG or .DocX when everything else is lower case.

As I’m learning Python, I put the following together.  Any improvements / optimizations are welcome of course.

[pastacode lang=”python” manual=”%23!%2Fusr%2Fbin%2Fpython3%0A%0A%23%20This%20script%20written%20on%20Linux%20Mint%2017.3%20with%20Python%203.4%0A%0Aimport%20sys%0Aimport%20os%0Aimport%20fnmatch%0Afrom%20pathlib%20import%20PurePath%20as%20ppath%0Aimport%20glob%20%23handles%20wildcards%20in%20listings%20better%0Aimport%20subprocess%0Aimport%20multiprocessing%20as%20mp%0A%0Aaction%20%3D%20%22%22%0Aworkinglist%20%3D%20%5B%5D%0A%0Amplist%20%3D%20mp.Queue()%0Ampcorelimit%20%3D%200%20%23limit%20number%20of%20processors%20used%0A%23%200%3Duse%20all%2C%20or%202%2C4%2C6%2C8%2C10%2C12%20.%20Consider%20drive%20I%2FO%2C%208-12%20generally%20okay%20with%20SSD’s%0A%0A%23———————————–%20%20Don’t%20recommend%20changes%20beneath%20this%20line%0A%0Adef%20errout(problem)%3A%0A%20%20%20%20print(problem)%0A%20%20%20%20exit(1)%0A%0Adef%20showhelp()%3A%0A%20%20%20%20print(‘fnametolower.py%20-%20filename%20to%20lower%20case%20(not%20foldernames%2C%20just%20files)’)%0A%20%20%20%20print(%22*%20Enclosing%20filenameorfilepattern%20in%20quotes%20is%20important%22)%0A%20%20%20%20%23%20because%20without%20quotes%2C%20python%20interprets%20every%20*.doc%20filename%20in%20current%20folder%20as%20a%20parameter%0A%20%20%20%20print(%22%22)%0A%20%20%20%20print(‘Usage%20%3A%20fnametolower.py%20%5B%20r%20%5D%20%22filenameorfilepattern%22’)%0A%20%20%20%20print(%22%20%20%20%20r%7CR%20-%20recurse%20current%20dir%20and%20down%22)%0A%20%20%20%20print(%22%22)%0A%20%20%20%20print(‘Example%20%3A%20%20%20fnametolower.py%20%22FileNumber%3F.JPG%22’)%0A%20%20%20%20print(‘%20%20%20%20%20%20%20%20%20%20%20%20fnametolower.py%20r%20%22*.DOCX%22’)%0A%20%20%20%20print(‘%20%20%20%20%20%20%20%20%20%20%20%20fnametolower.py%20r%20%22*%22’)%0A%20%20%20%20print(%22%22)%0A%20%20%20%20print(%22The%20way%20this%20script%20works%2C%20if%20you%20have%20a%20file%20called%20’r’%20in%20current%20folder%20then%20rename%20it%20by%20hand…%22)%0A%20%20%20%20exit(0)%0A%0Adef%20parseparams()%3A%0A%20%20%20%20returnlist%3D%5B%5D%0A%20%20%20%20args%20%3D%20%22%22%0A%20%20%20%20%23%20position%200%3Dself%2C%201%3Dflags%2C%202%3Dfile%20descriptors%0A%0A%20%20%20%20if%20len(sys.argv)%20%3D%3D%201%20or%20sys.argv%5B1%5D.lower()%20%3D%3D%20%22help%22%3A%0A%20%20%20%20%20%20%20%20showhelp()%0A%0A%20%20%20%20args%20%3D%20sys.argv%0A%20%20%20%20args.pop(0)%20%20%20%20%23%20don’t%20need%20position%20zero%20(scriptname)%0A%20%20%20%20action%20%3D%20str(args.pop(0).lower())%0A%20%20%20%20fullpath%20%3D%20os.path.abspath(action)%0A%0A%20%20%20%20if%20action.lower()%20!%3D%20%22r%22%3A%0A%20%20%20%20%20%20%20%20blob%20%3D%20glob.glob(fullpath)%20%23interprets%20wildcards%20%26%20absolute%20names%20correctly%0A%20%20%20%20%20%20%20%20for%20i%20in%20blob%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20returnlist.append(i)%0A%20%20%20%20%20%20%20%20return(action%2Creturnlist)%0A%0A%20%20%20%20else%3A%20%23process%20recursively%0A%20%20%20%20%20%20%20%20fullpath%20%3D%20os.path.abspath(str(args.pop(0).lower()))%0A%20%20%20%20%20%20%20%20pattern%20%3D%20os.path.basename(fullpath)%0A%20%20%20%20%20%20%20%20dirname%20%3D%20fullpath.rstrip(pattern)%0A%0A%20%20%20%20%20%20%20%20%23%20for%20this%20you%20have%20to%20os.walk%2Fenumerate%20all%20files%2C%20then%20find%20those%20that%20match%20filepattern%0A%20%20%20%20%20%20%20%20for%20root%2C%20dirs%2C%20files%20in%20os.walk(os.path.abspath(dirname))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20filename%20in%20fnmatch.filter(files%2Cpattern)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20returnlist.append(os.path.join(root%2C%20filename))%0A%20%20%20%20%20%20%20%20return(action%2Creturnlist)%0A%0Adef%20loweritem(infile)%3A%0A%20%20%20%20print(%22.%22%2C%20end%3D”)%0A%20%20%20%20fnameis%20%3D%20os.path.basename(infile)%0A%20%20%20%20pathis%20%3D%20infile.split(fnameis)%5B0%5D%0A%0A%20%20%20%20procresult%20%3D%20subprocess.os.rename(infile%2C%20pathis%2Bfnameis.lower())%0A%20%20%20%20return(str(procresult))%0A%0Adef%20tolower(workinglist)%3A%0A%20%20%20%20print(%22Renaming%20the%20following%20%22%20%2B%20str(len(workinglist))%20%2B%20%22%20files%3A%22)%0A%20%20%20%20for%20i%20in%20workinglist%3A%0A%20%20%20%20%20%20%20%20print(%22%20%20%20%20%22%20%2B%20str(i))%0A%20%20%20%20print(%22%22)%0A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20input(%22Hit%20ENTER%20to%20continue%20or%20CNTL-C%20to%20abort..%22)%0A%20%20%20%20except%3A%0A%20%20%20%20%20%20%20%20errout(%22Aborted%22)%0A%0A%20%20%20%20print(%22Working%22%2C%20end%3D”)%0A%0A%20%20%20%20%23define%20no.%20of%20CPU%20cores%20to%20be%20used%20for%20processing%0A%20%20%20%20%23%20assumes%20multithreading%2C%20thus%20the%20*2%0A%20%20%20%20pool%20%3D%20mp.Pool(processes%3Dmp.cpu_count()%20*%202)%0A%20%20%20%20if%20not%20mpcorelimit%20%3D%3D%200%20and%20pool%20%3E%20mpcorelimit%3A%0A%20%20%20%20%20%20%20%20pool%20%3D%20mpcorelimit%0A%0A%20%20%20%20pool_outputs%20%3D%20pool.map(loweritem%2C%20workinglist)%0A%20%20%20%20pool.close()%20%23%20no%20more%20tasks%20left%0A%20%20%20%20pool.join()%20%23%20wrap%20up%20tasks%20and%20join%0A%0A%20%20%20%20goodrun%3DTrue%0A%20%20%20%20for%20i%20in%20pool_outputs%3A%0A%20%20%20%20%20%20%20%20if%20not%20i%20%3D%3D%20%22None%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20goodrun%20%3D%20False%0A%20%20%20%20if%20goodrun%3A%0A%20%20%20%20%20%20%20%20return(True)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20print(%22*%20%20%20%20—-%20errors%20detected%22)%0A%20%20%20%20%20%20%20%20for%20i%20in%20pool_outputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(i)%0A%20%20%20%20%20%20%20%20return(False)%0A%0A%23main()%0Aaction%2C%20workinglist%20%3D%20parseparams()%0A%0Aif%20tolower(workinglist)%3A%20%23if%20processing%20returns%20True%0A%20%20%20%20print(%22Task%20completed.%22)%0Aelse%3A%20%23returned%20False%0A%20%20%20%20errout(%22problem%20with%20renaming%20detected%2C%20script%20halted%22)” message=”fnametolower.py” highlight=”” provider=”manual”/]
Leave A Reply