Created
March 7, 2026 10:06
-
-
Save daemondevin/dc0868321e325162ac4c120a7f752637 to your computer and use it in GitHub Desktop.
PHP CLI filename renamer with wildcard capture
This file contains hidden or 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
| <?php | |
| /** | |
| * CLI filename renamer with wildcard capture | |
| * | |
| * Example: | |
| * php replaceFilename.php --find=frontendadmin.*.php --replace=ts*.snippet.php --regex=* | |
| */ | |
| $options = getopt("", [ | |
| "find:", | |
| "replace:", | |
| "regex:", | |
| "dir::", | |
| "dry-run::", | |
| "recursive::" | |
| ]); | |
| if (!isset($options['find'], $options['replace'], $options['regex'])) { | |
| echo "Usage:\n"; | |
| echo "php replaceFilename.php --find=PATTERN --replace=PATTERN --regex=CHAR [--dir=PATH] [--dry-run] [--recursive]\n"; | |
| exit(1); | |
| } | |
| $findPattern = $options['find']; | |
| $replacePattern = $options['replace']; | |
| $regexToken = $options['regex']; | |
| $directory = $options['dir'] ?? getcwd(); | |
| $dryRun = array_key_exists('dry-run', $options); | |
| $recursive = array_key_exists('recursive', $options); | |
| if (!is_dir($directory)) { | |
| echo "Invalid directory: $directory\n"; | |
| exit(1); | |
| } | |
| /** | |
| * Convert the find pattern to regex | |
| */ | |
| function buildRegex($pattern, $token) { | |
| $escaped = preg_quote($pattern, '/'); | |
| $escaped = str_replace(preg_quote($token, '/'), '(.+)', $escaped); | |
| return '/^' . $escaped . '$/'; | |
| } | |
| /** | |
| * Build replacement filename | |
| */ | |
| function buildReplacement($pattern, $capture, $token) { | |
| return str_replace($token, $capture, $pattern); | |
| } | |
| $regex = buildRegex($findPattern, $regexToken); | |
| $total = 0; | |
| $renamed = 0; | |
| $skipped = 0; | |
| $iterator = $recursive | |
| ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)) | |
| : new IteratorIterator(new DirectoryIterator($directory)); | |
| foreach ($iterator as $file) { | |
| if (!$file->isFile()) { | |
| continue; | |
| } | |
| $filename = $file->getFilename(); | |
| if (preg_match($regex, $filename, $matches)) { | |
| $total++; | |
| $capture = $matches[1]; | |
| $newName = buildReplacement($replacePattern, $capture, $regexToken); | |
| $oldPath = $file->getPathname(); | |
| $newPath = $file->getPath() . DIRECTORY_SEPARATOR . $newName; | |
| if (file_exists($newPath)) { | |
| echo "SKIP (exists): $filename -> $newName\n"; | |
| $skipped++; | |
| continue; | |
| } | |
| if ($dryRun) { | |
| echo "DRY RUN: $filename -> $newName\n"; | |
| $renamed++; | |
| } else { | |
| if (rename($oldPath, $newPath)) { | |
| echo "RENAMED: $filename -> $newName\n"; | |
| $renamed++; | |
| } else { | |
| echo "FAILED: $filename\n"; | |
| $skipped++; | |
| } | |
| } | |
| } | |
| } | |
| echo "\n------ Summary ------\n"; | |
| echo "Matched : $total\n"; | |
| echo "Renamed : $renamed\n"; | |
| echo "Skipped : $skipped\n"; | |
| echo "Directory: $directory\n"; | |
| echo "Mode: " . ($dryRun ? "DRY RUN" : "LIVE") . "\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment