Skip to content

Instantly share code, notes, and snippets.

@achimmihca
Created January 12, 2022 14:39
Show Gist options
  • Save achimmihca/81433b60ba1bab5516bb84483b048e72 to your computer and use it in GitHub Desktop.
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.
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