The point is obvious. There is more than one way to burn a book. And the world is full of people running about with lit matches. Every minority ... feels it has the will, the right, the duty to douse the kerosene, light the fuse. Every dimwit editor who sees himself as the source of all dreary blanc-mange plain porridge unleavened literature, licks his guillotine and eyes the neck of any author who dares to speak above a whisper or write above a nursery rhyme.”
Ray Bradbury

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