fix: add simple search and replace script

This commit is contained in:
2026-06-05 11:59:26 +02:00
parent cad812d787
commit f299477d51
2 changed files with 132 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
import argparse
from pathlib import Path
import sys
def find_files(directory: Path, recursive: bool):
if recursive:
yield from (p for p in directory.rglob("*") if p.is_file())
else:
yield from (p for p in directory.iterdir() if p.is_file())
def process_file(file_path: Path, search: str, replace: str):
try:
content = file_path.read_text(encoding="utf-8")
except (UnicodeDecodeError, OSError):
return None
if search not in content:
return None
changed_lines = []
for lineno, line in enumerate(content.splitlines(), start=1):
if search in line:
changed_lines.append({
"line": lineno,
"old": line,
"new": line.replace(search, replace),
})
return {
"path": file_path,
"count": content.count(search),
"new_content": content.replace(search, replace),
"changed_lines": changed_lines,
}
def main():
parser = argparse.ArgumentParser(
description="Search and replace text in files with confirmation."
)
parser.add_argument(
"directory",
help="Directory to search"
)
parser.add_argument(
"search",
help="String to search for"
)
parser.add_argument(
"replace",
help="Replacement string"
)
parser.add_argument(
"-r",
"--recursive",
action="store_true",
help="Search recursively"
)
parser.add_argument(
"-y",
"--yes",
action="store_true",
help="Skip confirmation"
)
args = parser.parse_args()
directory = Path(args.directory)
if not directory.is_dir():
print(f"Error: '{directory}' is not a directory.", file=sys.stderr)
sys.exit(1)
changes = []
for file_path in find_files(directory, args.recursive):
result = process_file(file_path, args.search, args.replace)
if result:
changes.append(result)
if not changes:
print("No matches found.")
return
print("\nPlanned changes:\n")
total_replacements = 0
for change in changes:
print("=" * 80)
print(f"File: {change['path']}")
print(f"Replacements: {change['count']}")
print()
for line_change in change["changed_lines"]:
print(f"Line {line_change['line']}:")
print(f" - {line_change['old']}")
print(f" + {line_change['new']}")
print()
total_replacements += change["count"]
if not args.yes:
try:
response = input("\nApply these changes? [y/N]: ").strip().lower()
except KeyboardInterrupt:
print("Aborted")
sys.exit(1)
if response.lower() not in ("y", "yes"):
print("Aborted.")
return
for change in changes:
change["path"].write_text(
change["new_content"],
encoding="utf-8"
)
print(
f"Completed. Modified {len(changes)} file(s), "
f"{total_replacements} replacement(s)."
)
if __name__ == "__main__":
main()
+2
View File
@@ -263,3 +263,5 @@ cat() {
command cat "$file"
done
}
alias sr="~/.config/search_and_replace.py"