# Generate a Safe Rename Script

Paste an old,new filename mapping and get a safe bash mv or PowerShell Rename-Item script, correctly ordered and quoted, plus the matching undo script.

## Run it

- **CLI:** `gizza tool mv-script-generator "IMG_001.JPG,photo-001.jpg
IMG_002.JPG,photo-002.jpg"`
- **Web:** https://gizza.ai/tools/mv-script-generator/
- **Agents:** machine-readable descriptor (parameters JSON Schema) at https://gizza.ai/tools/mv-script-generator/tool.json

## Inputs

- `mapping` — Mapping (one old,new pair per line) _(field)_
- `format` — Mapping format _(field)_
- `shell` — Script dialect _(field)_
- `base_dir` — Run the script in this directory (optional) _(field)_
- `dry_run` — Dry run (report each move, don't perform it) _(field)_
- `overwrite` — Allow overwriting an existing destination _(field)_
- `mkdir_parents` — Create missing destination directories _(field)_
- `undo_script` — Also emit the undo script _(field)_
- `comments` — Include the summary header comment _(field)_

## Output

- Rename script (text)

## Query parameters

Open the tool pre-filled and auto-run via URL:

- `mapping` — Mapping (one old,new pair per line)
- `format` — Mapping format
- `shell` — Script dialect
- `base_dir` — Run the script in this directory (optional)
- `dry_run` — Dry run (report each move, don't perform it)
- `overwrite` — Allow overwriting an existing destination
- `mkdir_parents` — Create missing destination directories
- `undo_script` — Also emit the undo script
- `comments` — Include the summary header comment

Example: `https://gizza.ai/tools/mv-script-generator/?mapping=IMG_001.JPG%2Cphoto-001.jpg%0AIMG_002.JPG%2Cphoto-002.jpg&format=auto&shell=bash&base_dir=%2Fhome%2Fme%2Fphotos&dry_run=true&overwrite=true&mkdir_parents=true&undo_script=true&comments=true`

---

## About this tool

You already know what the files should be called — the risky part is writing the script that does it. Paste the `old,new` mapping and this tool emits the rename script for you, quoted correctly, ordered so nothing gets clobbered, and paired with an undo script. It runs entirely in your browser and never touches a file: the output is text you review, save, and run yourself.

Each line is one pair. Comma, tab, `|`, and ` -> ` all work, and auto-detect picks the one that fits every line. Blank lines and `#` comments are ignored, and a header row such as `old,new` is skipped.

Worked example — this mapping:

```text
IMG_001.JPG,photo-001.jpg
IMG_002.JPG,photo-002.jpg
```

produces this rename script (with the undo option off, for brevity):

```bash
#!/usr/bin/env bash
# Rename script generated by mv-script-generator — 2 renames.
# Review this script before running it. Nothing moves until you run it.
set -euo pipefail

mv_safe() {
  local src=$1 dst=$2
  if [ ! -e "$src" ] && [ ! -L "$src" ]; then
    printf 'mv-script: missing source: %s\n' "$src" >&2
    exit 1
  fi
  if [ -e "$dst" ] || [ -L "$dst" ]; then
    printf 'mv-script: destination exists: %s\n' "$dst" >&2
    exit 1
  fi
  mkdir -p -- "$(dirname -- "$dst")"
  mv -- "$src" "$dst"
}

mv_safe 'IMG_001.JPG' 'photo-001.jpg'
mv_safe 'IMG_002.JPG' 'photo-002.jpg'
```

### What the generator does that a hand-written loop usually doesn't

- **Ordering.** A chained mapping (`a → b`, `b → c`) is sorted so `b → c` runs first. Written in the order you typed it, `a → b` would destroy `b` before it was ever moved.
- **Cycles.** A straight swap (`a → b`, `b → a`) can't be ordered at all, so one side is staged through a `.mvtmp1` temp name and finished at the end — and the undo script unwinds through the same temp name.
- **Quoting.** Every path is single-quoted with dialect-correct escaping (`'\''` for POSIX, doubled `''` for PowerShell) and passed after `mv --` or via `-LiteralPath`, so spaces, apostrophes, `$HOME`, and leading dashes are all inert.
- **Collision checks.** Two lines renaming the same file, or two lines producing the same new name, are refused up front with both line numbers — before a script exists that could destroy something.
- **Guards at run time.** The emitted helper aborts on a missing source, and (unless you allow overwriting) on a destination that already exists.

### Options

- **Script dialect** — bash writes `set -euo pipefail` plus an `mv_safe` helper; PowerShell writes `$ErrorActionPreference = 'Stop'` plus a `Move-Safe` helper that uses `Rename-Item -LiteralPath` for same-directory renames and `Move-Item` when the destination changes folder.
- **Dry run** — bash prints `would move: old -> new` for each pair; PowerShell passes the `-WhatIf` switch.
- **Run in this directory** — prepends a quoted `cd --` / `Set-Location -LiteralPath` so your mapping can use bare filenames.
- **Create missing destination directories** — on by default, so `a.txt -> 2026/01/a.txt` works.
- **Undo script** — on by default; you get the reverse script under a second header in the same output.

### Limits and edge cases

- Up to 1000 rename pairs per run.
- A pair whose old and new name are identical is skipped and counted in the header comment; if every pair is like that, you get an error instead of an empty script.
- Filenames containing control characters are refused — they cannot be written safely into a script.
- The tool assumes each old name exists and each new name does not. It cannot check that, so the emitted script checks at run time and stops on the first problem.
- Nothing is executed here. Read the script before you run it, and prefer a dry run on the real directory first.

## FAQ

<details>
<summary>Does this tool rename my files?</summary>

No. It runs in your browser and only produces text. You copy or download the script, read it, and run it yourself in the directory you choose.

</details>

<details>
<summary>How do I get an old,new mapping in the first place?</summary>

Any two-column list works — a spreadsheet export, `ls` piped into a text editor, or the sibling bulk file renamer tool, which derives new names from find/replace, regex, numbering, or case rules and prints exactly the `old -> new` list this tool consumes.

</details>

<details>
<summary>What happens if two files need to swap names?</summary>

The generator detects the cycle and stages one file through a temp name: `a.txt` → `a.txt.mvtmp1`, then `b.txt` → `a.txt`, then `a.txt.mvtmp1` → `b.txt`. The undo script reverses the same three steps, so a swap is fully reversible.

</details>

<details>
<summary>My filenames contain commas. Will the CSV split break them?</summary>

Choose the CSV format and wrap the field in double quotes — `"report, final.txt",report-final.txt` — or switch to the tab, pipe, or arrow format instead. Auto-detect also skips a separator that doesn't split every line cleanly.

</details>

<details>
<summary>Why does the script refuse to overwrite an existing file?</summary>

Because an overwrite in a bulk rename is almost always a mistake that costs you a file. The default helper stops with `destination exists: <name>`. If replacing is what you want, tick the overwrite option and the script switches to `mv -f` / `-Force`.

</details>

<details>
<summary>Can I use absolute paths, or move files between folders?</summary>

Yes. A pair like `/tmp/in/a.txt,/srv/archive/2026/a.txt` is fine, and so is a relative destination in a subfolder. With "create missing destination directories" on, the parent folders are created first; the PowerShell script switches from `Rename-Item` to `Move-Item` automatically when the destination folder differs.

</details>

## Related tools

- [Apply a Unified Diff to a File](https://gizza.ai/tools/apply-patch/): Paste a file and a unified diff to get the patched text in your browser, with reverse apply, fuzz matching, and per-hunk conflict reports.
- [Autocomplete Trie](https://gizza.ai/tools/autocomplete-trie/): Build a prefix trie from a pasted wordlist and get ranked autocomplete suggestions for any typed prefix. Weights, typo tolerance, trie stats, JSON. Runs locally.
- [Code Chunker](https://gizza.ai/tools/code-chunker/): Split Python, Rust, JavaScript, TypeScript, Go, Java, C/C++, C#, PHP, or Swift into line-ranged chunks that keep functions and classes intact.
- [Code Formatter](https://gizza.ai/tools/code-formatter/): Beautify and re-indent minified or messy HTML, CSS, JavaScript, or JSON. Auto-detect the language, choose spaces or tabs, and format locally in your browser.
- [Code language detector](https://gizza.ai/tools/code-language-detect/): Detect the likely programming language of a pasted code snippet with ranked alternatives, confidence and explainable signals.
