More
| author |
Steve Losh <steve@stevelosh.com> |
| date |
Tue, 13 Oct 2026 10:31:54 -0400 |
| parents |
(none) |
| children |
(none) |
#!/usr/bin/env bash
set -eu
# Lists the current directory's files in Vim, so you can edit it and save to rename them
# USAGE: vimv [file1 file2]
# https://github.com/thameera/vimv
declare -r FILENAMES_FILE=$(mktemp "${TMPDIR:-/tmp}/vimv.XXXXXX")
trap '{ rm -f "${FILENAMES_FILE}" ; }' EXIT
safeMove() {
local src="$1"
local dest="$2"
mkdir -p "$(dirname "$dest")"
if [ -e "$dest" ]; then
echo "WARN: Can't rename '$src' -> '$dest', destination exists!" >&2
return 1
fi
if git ls-files --error-unmatch "$src" > /dev/null 2>&1; then
git mv -- "$src" "$dest"
else
mv -n -- "$src" "$dest"
fi
}
if [ $# -ne 0 ]; then
src=( "$@" )
else
IFS=$'\r\n' GLOBIGNORE='*' command eval 'src=($(ls -1A))'
fi
for ((i=0;i<${#src[@]};++i)); do
echo "${src[i]}" >> "${FILENAMES_FILE}"
done
${EDITOR:-vi} "${FILENAMES_FILE}"
IFS=$'\r\n' GLOBIGNORE='*' command eval 'dest=($(cat "${FILENAMES_FILE}"))'
IFS=$'\r\n' GLOBIGNORE='*' command eval 'dest_unique=($(cat "${FILENAMES_FILE}" | sort -u))'
if (( ${#src[@]} != ${#dest[@]} )); then
echo "WARN: Number of files changed. Did you delete a line by accident? Aborting.." >&2
exit 1
fi
if (( ${#dest[@]} != ${#dest_unique[@]} )); then
echo "WARN: Destination filenames are not unique! Aborting.." >&2
exit 1
fi
declare -i count=0
EXT="vimv-tmp-$(date +%s)-${RANDOM}"
for ((i=0;i<${#src[@]};++i)); do
if [ "${src[i]}" != "${dest[i]}" ]; then
safeMove "${src[i]}" "${dest[i]}.${EXT}" && ((++count))
fi
done
for ((i=0;i<${#src[@]};++i)); do
if [ "${src[i]}" != "${dest[i]}" ]; then
safeMove "${dest[i]}.${EXT}" "${dest[i]}" || : resume on error
fi
done
echo "$count" files renamed.