2020-03-15 14:19:05 +00:00
|
|
|
#!/usr/bin/env bash
|
2020-03-08 01:45:11 +00:00
|
|
|
|
|
|
|
# Description: An almost fully POSIX compliant batch file renamer
|
|
|
|
#
|
2020-03-11 12:22:38 +00:00
|
|
|
# Note: nnn auto-detects and invokes this plugin if available
|
2020-04-20 17:09:30 +00:00
|
|
|
# Whitespace is used as delimiter for read.
|
|
|
|
# The plugin doesn't support filenames with leading or trailing whitespace
|
2021-11-02 22:09:47 +00:00
|
|
|
# To use NNN_LIST your shell must support readlink(1)
|
2020-03-11 12:22:38 +00:00
|
|
|
#
|
|
|
|
# Capabilities:
|
|
|
|
# 1. Basic file rename
|
|
|
|
# 2. Detects order change
|
|
|
|
# 3. Can move files
|
|
|
|
# 4. Can remove files
|
|
|
|
# 5. Switch number pairs to swap filenames
|
|
|
|
#
|
2020-03-15 14:19:05 +00:00
|
|
|
# Shell: bash
|
2020-03-08 01:45:11 +00:00
|
|
|
# Author: KlzXS
|
|
|
|
|
2023-02-17 13:51:57 +00:00
|
|
|
# shellcheck disable=SC1090,SC1091
|
|
|
|
. "$(dirname "$0")"/.nnn-plugin-helper
|
|
|
|
|
2020-11-28 04:33:05 +00:00
|
|
|
EDITOR="${EDITOR:-vi}"
|
2020-03-08 01:45:11 +00:00
|
|
|
TMPDIR="${TMPDIR:-/tmp}"
|
2022-02-22 11:32:12 +00:00
|
|
|
NNN_INCLUDE_HIDDEN="${NNN_INCLUDE_HIDDEN:-0}"
|
2020-03-20 19:28:42 +00:00
|
|
|
VERBOSE="${VERBOSE:-0}"
|
2021-10-03 09:42:02 +00:00
|
|
|
RECURSIVE="${RECURSIVE:-0}"
|
2020-03-08 01:45:11 +00:00
|
|
|
|
2022-02-13 09:37:21 +00:00
|
|
|
case "$NNN_TRASH" in
|
|
|
|
1)
|
|
|
|
RM_UTIL="trash-put" ;;
|
|
|
|
2)
|
|
|
|
RM_UTIL="gio trash" ;;
|
|
|
|
*)
|
2024-02-13 13:32:42 +00:00
|
|
|
RM_UTIL="rm -ri --" ;;
|
2022-02-13 09:37:21 +00:00
|
|
|
esac
|
|
|
|
|
2020-03-08 01:45:11 +00:00
|
|
|
exit_status=0
|
|
|
|
|
2023-02-17 13:51:57 +00:00
|
|
|
if nnn_use_selection "Rename"; then
|
2023-02-17 14:12:07 +00:00
|
|
|
# shellcheck disable=SC2154
|
2020-03-08 01:45:11 +00:00
|
|
|
arr=$(tr '\0' '\n' < "$selection")
|
|
|
|
else
|
2021-10-03 09:42:02 +00:00
|
|
|
findcmd="find . ! -name ."
|
|
|
|
|
|
|
|
if [ "$RECURSIVE" -eq 0 ]; then
|
|
|
|
findcmd="$findcmd -prune"
|
|
|
|
fi
|
|
|
|
|
2022-02-22 11:32:12 +00:00
|
|
|
if [ "$NNN_INCLUDE_HIDDEN" -eq 0 ]; then
|
2021-10-03 09:42:02 +00:00
|
|
|
findcmd="$findcmd ! -name \".*\""
|
2020-03-08 01:45:11 +00:00
|
|
|
fi
|
2021-10-03 09:42:02 +00:00
|
|
|
|
2021-11-07 21:08:43 +00:00
|
|
|
if [ -z "$NNN_LIST" ]; then
|
|
|
|
findcmd="$findcmd -print"
|
|
|
|
else
|
|
|
|
findcmd="$findcmd -printf "'"'"$NNN_LIST/%P\n"'"'
|
|
|
|
fi
|
2021-10-03 09:42:02 +00:00
|
|
|
|
|
|
|
arr=$(eval "$findcmd" | sort)
|
2020-03-08 01:45:11 +00:00
|
|
|
fi
|
|
|
|
|
2020-04-20 17:09:30 +00:00
|
|
|
lines=$(printf "%s\n" "$arr" | wc -l)
|
|
|
|
width=${#lines}
|
|
|
|
|
2023-02-19 15:14:53 +00:00
|
|
|
dst_file=$(mktemp "$TMPDIR/.nnnXXXXXX")
|
2024-02-13 13:32:42 +00:00
|
|
|
trap 'rm -f -- "$dst_file"' EXIT
|
2023-02-19 15:14:53 +00:00
|
|
|
|
2020-04-20 17:09:30 +00:00
|
|
|
printf "%s" "$arr" | awk '{printf("%'"${width}"'d %s\n", NR, $0)}' > "$dst_file"
|
2020-03-08 01:45:11 +00:00
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
items=("~")
|
|
|
|
while IFS='' read -r line; do
|
2021-11-10 20:56:51 +00:00
|
|
|
if [ -n "$NNN_LIST" ]; then
|
2021-11-02 22:09:47 +00:00
|
|
|
line=$(readlink "$line" || printf "%s" "$line")
|
|
|
|
fi
|
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
items+=("$line");
|
|
|
|
done < <(printf "%s\n" "$arr")
|
|
|
|
|
2020-03-08 01:45:11 +00:00
|
|
|
$EDITOR "$dst_file"
|
|
|
|
|
|
|
|
while read -r num name; do
|
|
|
|
if [ -z "$name" ]; then
|
|
|
|
if [ -z "$num" ]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
printf "%s: unable to parse line, aborting\n" "$0"
|
2020-03-11 12:20:55 +00:00
|
|
|
exit 1
|
2020-03-08 01:45:11 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
# check if $num is an integer
|
|
|
|
if [ ! "$num" -eq "$num" ] 2> /dev/null; then
|
|
|
|
printf "%s: unable to parse line, aborting\n" "$0"
|
2020-03-11 12:20:55 +00:00
|
|
|
exit 1
|
2020-03-08 01:45:11 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
src=${items[$num]}
|
2020-03-08 01:45:11 +00:00
|
|
|
|
|
|
|
if [ -z "$src" ]; then
|
|
|
|
printf "%s: unknown item number %s\n" "$0" "$num" > /dev/stderr
|
|
|
|
continue
|
|
|
|
elif [ "$name" != "$src" ]; then
|
|
|
|
if [ -z "$name" ]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ! -e "$src" ] && [ ! -L "$src" ]; then
|
|
|
|
printf "%s: %s does not exit\n" "$0" "$src" > /dev/stderr
|
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
unset "items[$num]"
|
2020-03-08 01:45:11 +00:00
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
# handle swaps
|
|
|
|
if [ -e "$name" ] || [ -L "$name" ]; then
|
|
|
|
tmp="$name~"
|
|
|
|
c=0
|
|
|
|
|
|
|
|
while [ -e "$tmp" ] || [ -L "$tmp" ]; do
|
|
|
|
c=$((c+1))
|
|
|
|
tmp="$tmp~$c"
|
|
|
|
done
|
|
|
|
|
2024-02-13 13:32:42 +00:00
|
|
|
if mv -- "$name" "$tmp"; then
|
2020-03-20 19:28:42 +00:00
|
|
|
if [ "$VERBOSE" -ne 0 ]; then
|
|
|
|
printf "'%s' -> '%s'\n" "$name" "$tmp"
|
|
|
|
fi
|
2020-03-08 01:45:11 +00:00
|
|
|
else
|
|
|
|
printf "%s: failed to rename %s to %s: %s\n" "$0" "$name" "$tmp" "$!" > /dev/stderr
|
|
|
|
exit_status=1
|
|
|
|
fi
|
2020-03-15 14:56:53 +00:00
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
for key in "${!items[@]}"; do
|
|
|
|
if [ "${items[$key]}" = "$name" ]; then
|
|
|
|
items[$key]="$tmp"
|
2020-03-08 01:45:11 +00:00
|
|
|
fi
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
|
|
|
|
dir=$(dirname "$name")
|
|
|
|
if [ ! -d "$dir" ] && ! mkdir -p "$dir"; then
|
|
|
|
printf "%s: failed to create directory tree %s\n" "$0" "$dir" > /dev/stderr
|
|
|
|
exit_status=1
|
2024-02-13 13:32:42 +00:00
|
|
|
elif ! mv -i -- "$src" "$name"; then
|
2020-03-08 01:45:11 +00:00
|
|
|
printf "%s: failed to rename %s to %s: %s\n" "$0" "$name" "$tmp" "$!" > /dev/stderr
|
|
|
|
exit_status=1
|
|
|
|
else
|
|
|
|
if [ -d "$name" ]; then
|
2020-03-15 14:19:05 +00:00
|
|
|
for key in "${!items[@]}"; do
|
|
|
|
items[$key]=$(printf "%s" "${items[$key]}" | sed "s|^$src\(\$\|\/\)|$name\1|")
|
2020-03-08 01:45:11 +00:00
|
|
|
done
|
2020-03-15 14:56:53 +00:00
|
|
|
|
2020-03-20 19:28:42 +00:00
|
|
|
if [ "$VERBOSE" -ne 0 ]; then
|
|
|
|
printf "'%s' => '%s'\n" "$src" "$name"
|
|
|
|
fi
|
2020-03-08 01:45:11 +00:00
|
|
|
else
|
2020-03-20 19:28:42 +00:00
|
|
|
true
|
|
|
|
if [ "$VERBOSE" -ne 0 ]; then
|
|
|
|
printf "'%s' -> '%s'\n" "$src" "$name"
|
|
|
|
fi
|
2020-03-08 01:45:11 +00:00
|
|
|
fi
|
|
|
|
fi
|
2020-03-15 14:19:05 +00:00
|
|
|
fi
|
2020-03-08 01:45:11 +00:00
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
unset "items[$num]"
|
2020-03-08 01:45:11 +00:00
|
|
|
done <"$dst_file"
|
|
|
|
|
2020-03-15 14:19:05 +00:00
|
|
|
unset "items[0]"
|
|
|
|
for item in "${items[@]}"; do
|
2022-02-13 09:37:21 +00:00
|
|
|
$RM_UTIL "$item"
|
2020-03-08 01:45:11 +00:00
|
|
|
done
|
|
|
|
|
|
|
|
exit $exit_status
|