Created
January 12, 2022 14:39
-
-
Save achimmihca/81433b60ba1bab5516bb84483b048e72 to your computer and use it in GitHub Desktop.
Add (prepend or append) text to files in a given folder. Thereby, file name and folder path are available as placeholders.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import glob | |
import os | |
import re | |
import ntpath | |
import sys | |
import argparse | |
from typing import List | |
# Example how this script can be called: | |
# python this-script.py --fileExtensions "txt" --prepend --onlyIfNew --ignorePathRegEx ".*ignore-me.*" --text "Hello {filename}!{newline}" | |
class CommandLineArgsParser: | |
def __init__(self) -> None: | |
# Init ArgumentParser | |
self.argumentParser = argparse.ArgumentParser(description='Add text to files in a given folder.\n' | |
'Available placeholders are: {newline}, {filefolder}, {filename}') | |
# Configure available arguments | |
self.argumentParser.add_argument("--prepend", action='store_true', | |
help='Prepend the text') | |
self.argumentParser.add_argument("--append", action='store_true', | |
help='Append the text') | |
self.argumentParser.add_argument("--onlyIfNew", action='store_true', | |
help='Add the text to a file only if it is not found in the file yet') | |
self.argumentParser.add_argument("--text", type=str, | |
help='The text to be added') | |
self.argumentParser.add_argument("--folder", type=str, default="", | |
help='Folder to search files in.' | |
'\nIf none is given, then the current working directory is used.') | |
self.argumentParser.add_argument("--fileExtensions", type=str, default="", | |
help='Comma separated value of file extensions.\n' | |
'If none is given, then all files are used.') | |
self.argumentParser.add_argument("--ignorePathRegEx", type=str, default="", | |
help='RegEx for file paths to be ignored. Must match the whole path.\n' | |
'If none is given, then no files are ignored.\n' | |
'Example: "(.*ignore-me.*)|(.*ignore-me-too.*)"') | |
self.argumentParser.add_argument("--includePathRegEx", type=str, default="", | |
help='RegEx for file paths to be included. Must match the whole path.\n' | |
'If none is given, then all files are included.' | |
'\nExample: "(.*include-me.*)|(.*include-me-too.*)"') | |
# Parse command line | |
parsed_args = self.argumentParser.parse_args() | |
# Set properly typed fields corresponding to the given command line arguments | |
self.isPrepend: bool = parsed_args.prepend | |
self.isAppend: bool = parsed_args.append | |
self.isOnlyIfNew: bool = parsed_args.onlyIfNew | |
self.text: str = parsed_args.text | |
self.folder: str = parsed_args.folder | |
self.ignorePathRegEx: str = parsed_args.ignorePathRegEx | |
self.includePathRegEx: str = parsed_args.includePathRegEx | |
self.fileExtensions: List[str] = parsed_args.fileExtensions.split(",") if parsed_args.fileExtensions else [] | |
def getTextWithResolvedPlaceholders(self, path: str) -> str: | |
path = path.replace("\\", "/") | |
folderPath = ntpath.dirname(path) | |
fileName = ntpath.basename(path) | |
return (self.text | |
.replace("{newline}", "\n") | |
.replace("{filename}", fileName) | |
.replace("{filefolder}", folderPath)) | |
def printHelp(self) -> None: | |
self.argumentParser.print_help() | |
def addTextToFile(path: str, text: str, prepend: bool, append: bool, onlyIfNew: bool) -> None: | |
with open(path, "r", encoding="utf-8") as fileHandle: | |
fileContent = fileHandle.read() | |
if onlyIfNew and text in fileContent: | |
print(f"Skipping '{path}'. Text already found in file.") | |
return | |
if prepend: | |
fileContent = text + fileContent | |
if append: | |
fileContent = fileContent + text | |
with open(path, "w", encoding="utf-8") as fileHandle: | |
fileHandle.write(fileContent) | |
fileHandle.close() | |
print(f"Added text to '{path}'") | |
def getFileExtension(path: str) -> str: | |
fileExtensionWithDot = os.path.splitext(path)[1] | |
fileExtensionWithoutDot = fileExtensionWithDot if len(fileExtensionWithDot) <= 0 else fileExtensionWithDot[1:] | |
return fileExtensionWithoutDot.lower() | |
############################################################### | |
commandLineArgs = CommandLineArgsParser() | |
# Validate command line arguments | |
if not commandLineArgs.text: | |
print("No text specified", file=sys.stderr) | |
commandLineArgs.printHelp() | |
exit(1) | |
# Find folder | |
folder: str = commandLineArgs.folder \ | |
if len(commandLineArgs.folder) > 0 \ | |
else os.getcwd() | |
fileExtensionInfoMessage = f" with file extension {', '.join(commandLineArgs.fileExtensions)}" \ | |
if len(commandLineArgs.fileExtensions) > 0 \ | |
else "" | |
print(f"Adding text '{commandLineArgs.text}' to all files in '{folder}'{fileExtensionInfoMessage}") | |
# Find files | |
allFiles: List[str] = [f for f in glob.glob(f"{folder}/**", recursive=True) if os.path.isfile(f)] | |
allFiles = [f.replace("\\", "/") for f in allFiles] | |
# Filter files | |
if len(commandLineArgs.fileExtensions) > 0: | |
allFiles = [f for f in allFiles if (getFileExtension(f) in commandLineArgs.fileExtensions)] | |
if len(commandLineArgs.ignorePathRegEx) > 0: | |
allFiles = [f for f in allFiles if (re.match(commandLineArgs.ignorePathRegEx, f) is None)] | |
if len(commandLineArgs.includePathRegEx) > 0: | |
allFiles = [f for f in allFiles if (re.match(commandLineArgs.includePathRegEx, f) is not None)] | |
print(f"Found {len(allFiles)} files") | |
# Process files | |
for f in allFiles: | |
addTextToFile(f, commandLineArgs.getTextWithResolvedPlaceholders(f), commandLineArgs.isPrepend, commandLineArgs.isAppend, commandLineArgs.isOnlyIfNew) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment