# REName with Numbers - a .sh (dash; bash; zsh - compatible) rename script
# that can do basic arithmetic operations (+, -, padding with 0's) on
# numbers in file names
Disclaimer:
By using this program you are assuming full responsibility (and the
author of this program shall not be held liable) for any data loss
or damage that may result from the use or misuse of this program.
DetectShell () {
eval $1="";
if [ -n "$BASH_VERSION" ]; then
eval $1="bash";
elif [ -n "$ZSH_VERSION" ]; then
eval $1="zsh";
elif [ "$PS1" = '$ ' ]; then
eval $1="dash";
else
eval $1="undetermined";
fi
}
GetCharsArray () {
DestroyArray $2
eval str=\"\$$1\"
i1=0;
qm_mask=""
if [ -z "$str" ]; then
eval $2\_0="0";
else
rem_str="$str"
while [ "$i1" -le 1000000000 ]; do
i1=$((i1+1));
rem_str="${rem_str#?}"
qm_mask="$qm_mask?"
if [ -z "$rem_str" ]; then
break;
fi
done
eval $2\_0="$i1"
i2=1;
while [ "$i2" -le "$i1" ]; do
qm_mask="${qm_mask#?}"
eval crt_char=\"\$\{str\%$qm_mask\}\"
str="${str#?}"
eval $2\_$i2="\"\$crt_char\""
i2=$((i2+1))
done
fi
}
GetStrLen () {
eval str="$$1"
str_len=0;
qm_mask=""
if [ -z "$str" ]; then
eval $2="0";
else
rem_str="$str"
while [ "$str_len" -le 1000000000 ]; do
str_len=$((str_len+1));
rem_str="${rem_str#?}"
qm_mask="$qm_mask?"
if [ -z "$rem_str" ]; then
break;
fi
done
eval $2="$str_len"
fi
}
DestroyArray () {
eval array_len=$(($1_0))
j=0;
while [ "$j" -lt "$array_len" ]; do
j=$((j+1))
unset $1\_$j
done
unset $1\_0
}
ValidateNaturalNumber () {
eval tested_number="$$1"
condition="$tested_number -ge 0" #test if natural number
result="true"
if [ -n "$tested_number" ]; then
eval [ $condition ] 2>/dev/null || {
result="false";
}
fi
eval $2=$result
}
ProcedureGetMarginsAndNumber () {
eval input_f_n=\"\$$1\"
neg_number_detected="false"
if [ -n "$pylon1_mask1" ]; then
margin1="${input_f_n%%"$pylon1_mask1"*[0-9]*"$pylon2_mask1"*}"
else
if [ "${input_f_n%%"-"[0-9]*"$pylon2_mask1"*}" = "$input_f_n" ]; then #if a negative number is not match:
margin1="${input_f_n%%[0-9]*"$pylon2_mask1"*}"
else #if a negative number is match:
margin1="${input_f_n%%"-"[0-9]*"$pylon2_mask1"*}"
neg_number_detected="true"
fi
fi
if [ -n "$pylon2_mask1" ]; then
margin2="${input_f_n##"$margin1""$pylon1_mask1"*[0-9]*"$pylon2_mask1"}"
else
if [ "$neg_number_detected" = "false" ]; then #if a negative number is not match:
margin2="${input_f_n##"$margin1""$pylon1_mask1"*[0-9]}"
else #if a neg number is match:
margin2="${input_f_n##"$margin1""$pylon1_mask1"*"-"[0-9]}"
fi
fi
number_temp="${input_f_n#"$margin1""$pylon1_mask1"}"
number="${number_temp%"$pylon2_mask1""$margin2"}"
}
PrintInTitle () {
printf "\033]0;%s\007" "$1"
}
PrintJustInTitle () {
PrintInTitle "$1">/dev/stdin
}
CleanUp () {
#Restore CTRL-C, CTRL-Z:
trap - INT
trap - TSTP
DestroyArray params
DestroyArray rn_from
DestroyArray rn_to
DestroyArray numbers
DestroyArray margin1
DestroyArray margin2
DestroyArray marks_temp_fns
DestroyArray coll_chk_1_markings
DestroyArray marks_special_temp_fns
#Restore the initial directory:
cd "$initial_dir"
#Clear the title:
PrintJustInTitle ""
#Restore IFS:
IFS="$old_IFS"
}
trap1 () {
if [ "$started_rn" = "false" ]; then
printf "Cleaning up. Please wait..."
CleanUp
SPACE=" "
BS="\b"
SPACE_str=""
BS_str=""
for i in $(seq 1 40); do SPACE_str="$SPACE_str""$SPACE"; done
for i in $(seq 1 40); do BS_str="$BS_str""$BS"; done
printf "$BS_str"
printf "$SPACE_str"
printf "$BS_str"
printf "Aborted. Nothing done.\n"
exit
fi
}
DisplayHelp () {
printf "\n"
printf "renn - REName with Numbers\n"
printf "\n"
printf " Description:\n"
printf " - renames filenames in a directory that match a mask (<mask1>) inexactly:\n"
printf " - e.g.: <mask1>="(@)" matches "(@)"\n"
printf " - a '@' wildcard represents a number in the matched file/folder names.\n"
printf " - note that the first match is taken into consideration - so the strings surrounding the '@' mask character should uniquelly identify the matched number in each file/folder name\n"
printf "\n"
printf " Syntax:\n"
printf " renn <mask1> <mask2> <directory_path> [<condition>] [flags]\n"
printf " where:\n"
printf " <mask1> is a string containing exactly one '@' wildcard.\n"
printf " <mask2> is a string containing one "[...]" arithmetic expression.\n"
printf " An arithmetic expression is of the form "[expr(i)]", where:\n"
printf " "i" is a variable containing the number that the "@" wildcard replaces for each file/folder name\n"
printf " "expr(i)" represents an arithmetic expression containing any of: the variable "i" (without the $ in front of it), "-", "+", "(", ")", SPACE, TAB. Note that only addition and substraction are permitted - this is with of scope of not loosing information from file names\n"
printf " To pad the current arithmetic expression evaluation ("expr(i)") with N zeroes use the syntax: "[(0N)expr(i)]"\n"
printf " Example of arithmetic expression: [i+1]\n"
printf " <directory_path> represents the directory in which to try to match <mask1> and in which to perform the rename operation.\n"
printf " <condition>:\n"
printf " A { <condition> } has the syntax of an "if [ <condition> ]; then" statement, in which "-o" (logical OR) and "-a" (logical AND) can be used, except for the fact that the variable "i" is used without the character $ in front (i.e.: i and not $i). See above what "i" represents.\n"
printf " Like with the "if" syntax, subconditions can be grouped with escaped paranthesis: (, )\n"
printf " For example: { (i -ge 10 -a i -le 100) -o (i -ge 210 -a i -le 300) } - represents a valid condition\n"
printf " [flags] can be:\n"
printf " --help or -h\n"
printf " Displays this help information\n"
printf " --install or -i\n"
printf " Creates an executable symbolic link, in the location (directory) of the script\n"
printf " --file or -f\n"
printf " Tries to match file names (default)\n"
printf " --dir or -d\n"
printf " Tries to match directory names\n"
printf " --preview or -p\n"
printf " Previews the rename operation instead of properly renaming\n"
printf "\n"
printf " Recommendations/Notes:\n"
printf " To avoid unexpected behaviour, always quote parameters.\n"
printf " In order for this program to work correctly: new files must not be added and files must not be renamed/deleted in "<directory_path>", while the program is running!\n"
printf " Also, the rename operation shall not be interrupted (there are two major steps: Analyze and Preview/Rename).\n"
printf " For more complex file name opperations, this script can be used together with the "mmv" utility\n"
printf " Please note that: if they contain the newline character in them:\n"
printf " - file names are ignored\n"
printf " - masks are not handled properly\n"
printf " When temporary file name collision is detected, the "▄" character is used at the beginning of the file names for two step rename\n"
printf "\n"
}
MAIN START
#Store initial IFS:
old_IFS="$IFS"
IFS=" $(printf "\t")
";
started_rn="false"
E="ERROR"
DetectShell crt_shell
#Trap CTRL-C, CTRL-Z:
trap 'trap1' INT
trap 'trap1' TSTP
err="false"
ls -1 "/dev/null">/dev/null 2>/dev/null || {
printf "\n$E: "ls -1" (list one file per line) is needed in order for this program to function correctly!\n\n"
err="true"
}
printf "test"|sort -n>/dev/null 2>/dev/null || {
printf "\n$E: "sort -n" (numeric sort) is needed in order for this program to function correctly!\n\n"
err="true"
}
if [ "$err" = "true" ]; then
CleanUp && exit 1
fi
#Get the program parameters into the array "params":
count=0
for i; do
count=$((count+1))
eval params_$count="$i"
done
params_0=$((count))
if [ "$params_0" = "0" ]; then #if no parameters are provided: display help
DisplayHelp
CleanUp && exit 0
fi
#Create a flags array. A flag denotes special parameters:
help_flag="0"
install_flag="0"
file_flag="0"
directory_flag="0"
preview_flag="0"
i=1;
j=0;
while [ "$i" -le "$((params_0))" ]; do
eval params_i="${params_$i}"
case "${params_i}" in
"--help" | "-h" )
help_flag="1"
;;
"--install" | "-i" )
install_flag="1"
;;
"--file" | "-f" )
file_flag="1"
;;
"--dir" | "-d" )
directory_flag="1"
;;
"--preview" | "-p" )
preview_flag="1"
;;
* )
j=$((j+1))
eval selected_params_$j=\"\$params_i\"
;;
esac
i=$((i+1))
done
selected_params_0=$j
#Rebuild params array:
DestroyArray params
for i in $(seq 1 $selected_params_0); do
eval params_$i="${selected_params_$i}"
done
params_0=$selected_params_0
if [ "$help_flag" = "1" ]; then
DisplayHelp
elif [ "$install_flag" = "1" ]; then
file_path="$0"
file_name_plus_ext="${file_path##*/}"
file_dir_path="${file_path%/*}"
file_name="${file_name_plus_ext%.*}"
link_name="$file_name"
install_path="$file_dir_path"
#Install script (doesn't require root):
{
cd "$install_path"
} && {
ln -sfn "$file_name_plus_ext" "$link_name" #Create the link (or override/update it)
} && {
chmod u+x "$link_name" #Make the link 'executable' (+x) for the current user (u)"
} && {
printf '%s\n' "If not done already, please update the PATH variable (for the current user) by adding the next line to the end of \"~/.bashrc\" file or \"~/.zshrc\" (depending on the shell used) file:"
printf '\n%s\n\n' "export PATH=\"\$PATH:\"'$install_path' #This is for updating the PATH variable"
printf "and then close and reopen the terminal, in order for the new PATH to be loaded.\n"
}||{
printf '\n%s\n\n' "Could not install to the location: \"$install_path\"!"
CleanUp && exit 1
}
else
#RUN PROGRAM
PrintJustInTitle "A: Initialising, please wait..."
if [ "$directory_flag" = "1" ]; then
if [ ! "$file_flag" = "1" ]; then
dir="-d"; file="-d"
else
dir="-d"; file="-f"
fi
else
dir="-f"; file="-f" #(default)
fi
err="false"
#Detect paths, conditions and parameters that are not paths or conditions:
i=3; #count - jump over <mask1> and <mask2>
p=0; #number of parameters that are paths
c=0; #number of parameters that are conditions
n=0; #number of parameters that are not paths or conditions
extra_cond="\$i -eq \$i" #this condition is used to test if "$i" is a number or not
one_cond="1 -eq 1" #default value in case one_cond is not set further
while [ "$i" -le "$params_0" ]; do
eval params_i=\"\$params_$i\"
GetCharsArray params_i params_i_chars_array
first_char="$params_i_chars_array_1"
eval last_char=\"\$params_i_chars_array_$params_i_chars_array_0\"
if [ "$first_char" = "{" -a "$last_char" = "}" ]; then
c=$((c+1))
one_cond="${params_i#?}" #? = Remove "{" prefix:
one_cond="${one_cond%?}" # %? = Remove "}" suffix:
GetCharsArray one_cond one_cond_chars_array
j=1
new_one_cond="" #new_one_cond should contain i replaced with $i
while [ "$j" -le "$one_cond_chars_array_0" ]; do
eval crt_char=\"\$one_cond_chars_array_$j\"
if [ "$crt_char" = "i" ]; then
new_one_cond="$new_one_cond""\$i"
else
new_one_cond="$new_one_cond""$crt_char"
fi
j=$((j+1))
done
one_cond="$new_one_cond"
elif [ \( "$params_i" = "." -o "$params_i_chars_array_1$params_i_chars_array_2" = "./" -o "$params_i_chars_array_1$params_i_chars_array_2$params_i_chars_array_3" = "../" -o "$params_i_chars_array_1" = "/" \) ]; then #if a path is detected
p=$((p+1))
one_path="$params_i"
else
n=$((n+1))
fi
i=$((i+1))
done
set +f #enable globbing
mask1="$params_1"
mask2="$params_2"
directory="$one_path"
printf 'mask1="%s"\n' "$mask1"
printf 'mask2="%s"\n' "$mask2"
printf 'directory="%s"\n' "$directory"
if [ ! "$c" = "0" ]; then
printf '%s\n' "Condition = $one_cond"
fi
printf "\n"
err=false
if [ "$mask1" = "" ]; then
printf "$E: <mask1> must not be empty!\n"
err=true
fi
if [ "$mask2" = "" ]; then
printf "$E: <mask2> must not be empty!\n"
err=true
fi
#mask1 must contain a "@" character = number wildcard:
first_rem_part="${mask1#*"@"}"
if [ ! "$first_rem_part" = "${mask1}" ]; then #mask1 contains @
second_rem_part="${first_rem_part#*"@"}"
if [ ! "$second_rem_part" = "${first_rem_part}" ]; then #mask1 contains two @
printf "$E: <mask1> must contain exactly one @ wildcard!\n"
err=true
fi
else #mask1 does not contain @
printf "$E: <mask1> must contain the @ wildcard!\n"
err=true
fi
if [ "$directory" = "" ]; then
printf "$E: <directory_path> must not be empty (must be \".\" or start with \"./\" or \"/\")!\n"
err=true
fi
if [ -n "$mask1" -a "${mask1%%*"/"*}" = "" ]; then
printf "$E: <mask1> must not contain directory sepparators ('/')!\n"
err=true
fi
if [ -n "$mask2" -a "${mask2%%*"/"*}" = "" ]; then
printf "$E: <mask2> must not contain directory sepparators ('/')!\n"
err=true
fi
if [ "$n" -gt "0" ]; then
printf "$E: Too many parameters: expected <mask1>, <mask2>, <directory_path> and eventually <condition>!\n"
err="true"
fi
if [ "$p" -gt "1" ]; then
printf "\n$E: Too many <directory_path> parameters provided: expected one after <mask1> and <mask2>!\n"
err="true"
fi
if [ "$c" -gt "1" ]; then
printf "\n$E: Too many <condition> parameters provided: expected one after <mask1> and <mask2>!\n"
err="true"
fi
if [ "$err" = "true" ]; then
printf "\n"
CleanUp && exit 1
fi
rn_from_0=0
#<mask1> contains exactly one @ wildcard
#Generate pylon1 and pylon2 for mask1:
pylon1_mask1="${mask1%%"@"*}"
pylon2_mask1="${mask1#*"@"}"
#Generate pylon1 and pylon2 for mask2:
pylon1_mask2="${mask2%%"["*}"
pylon2_mask2="${mask2##*"]"}"
#Detect arithmetic expression:
found_arith_expr="true"
arith_expr="$mask2"
if [ "${mask2#*"["}" = "$mask2" ]; then
found_arith_expr="false"
else
arith_expr="${mask2#*"["}"
if [ "${arith_expr%"]"*}" = "$arith_expr" ]; then
found_arith_expr="false"
else
arith_expr="${arith_expr%"]"*}"
fi
fi
if [ "$found_arith_expr" = "false" ]; then
printf "\n$E: Expected at least one non-empty arithmetic expression ([...]) in <mask2>!\n\n"
CleanUp && exit 1
fi
#Validate arithmetic expression (characters permitted are +, -, SPACE, TAB, (, ) and i ):
GetCharsArray arith_expr arith_expr_chars_array
#Count special characters in arithmetic expression:
i=1;
count=0;
while [ "$i" -le "$arith_expr_chars_array_0" ]; do
eval crt_char=\"\$arith_expr_chars_array_$i\"
case "$crt_char" in
[0-9] | " " | "\t" | "+" | "-" | "(" | ")" | "i" )
count=$((count+1))
;;
esac
i=$((i+1))
done
if [ "$arith_expr_chars_array_0" -gt "$count" ]; then
printf "\n$E: Characters not permited in arithmetic expression (the characters permitted are: +, -, SPACE, TAB, (, ) and i)!\n\n"
CleanUp && exit 1
fi
#Check if the arithmetic expression has padding activated:
#initially, assume no padding:
arith_expr_padding="false"
arith_expr_wo_padding="${arith_expr#"(0"*")"}"
if [ -n "$arith_expr" ]; then
if [ -n "$arith_expr_wo_padding" ]; then
arith_expr_padding="${arith_expr%"$arith_expr_wo_padding"}"
arith_expr_padding_number="${arith_expr_padding#"(0"}"
arith_expr_padding_number="${arith_expr_padding_number%")"}"
ValidateNaturalNumber arith_expr_padding_number result
if [ "$result" = "true" ]; then
#remove padding from the arithmetic expression:
arith_expr="$arith_expr_wo_padding"
else
printf "\n$E: Invalid padding, in arithmetic expression!\n\n"
CleanUp && exit 1
fi
else
printf "\n$E: Number expected after padding, in arithmetic expression!\n\n"
CleanUp && exit 1
fi
else
printf "\n$E: Arithmetic expression must not be empty!\n\n"
CleanUp && exit 1
fi
initial_dir="$PWD" #Store initial dir
cd "$directory" 1>/dev/null 2>&1||{
printf '\n%s\n\n' "$E: Cannot access directory: \"$directory\"!"
CleanUp && exit 1
}
#Proceed to find matching file names and store them in numerically sorted order:
#Check file names starting with "▄" (error):
j=0
k=0
current_IFS="$IFS";
IFS="
";
err="false"
for f in $(ls -1|sort -n); do
j=$((j+1))
PrintJustInTitle "A: Step 1 of 4 - checking file name ${j}..."
if [ ! "$f" = "${f#"▄"}" ]; then #first char is "▄"
printf '%s\n' "$E: The first character of \"$f\" is \"▄\" (probably remainings from a interrupted temporary rename)!"
err="true"
elif [ ! \( "$err" = "true" \) -a \( \( $file "$f" \) -o \( $dir "$f" \) \) ]; then
case $f in
*"$pylon1_mask1"*[0-9]*"$pylon2_mask1"* ) #$f is match for <mask1>
ProcedureGetMarginsAndNumber f
i=$number
eval [ \\\( $extra_cond \\\) -a \\\( $one_cond \\\) ] 2>/dev/null && {
#If <condition> is met:
#input file name = margin1 pylon1_mask1 number pylon2_mask1 margin2
k=$((k+1))
eval rn_from_$k=\"\$f\"
eval numbers_$k=\"\$number\"
eval margin1_$k=\"\$margin1\"
eval margin2_$k=\"\$margin2\"
}
;;
esac
fi
done
IFS="$current_IFS";
eval rn_from_0=$((k))
if [ "$err" = "true" ]; then
printf "\n"
CleanUp && exit 1
fi
if [ "$rn_from_0" = "0" ]; then
printf "\nNo file names match the specified mask!\n\n"
CleanUp && exit 0
fi
#Generate 'renamed to' file names:
arith_err_encountered="false"
for ii in $(seq 1 $rn_from_0); do
PrintJustInTitle "A: Step 2 of 4: file name $ii of ${rn_from_0}..."
#output file name = margin1 pylon1_mask2 arith_expr(number) pylon2_mask2 margin2
eval new_f_n=\"\$margin1_$ii\$pylon1_mask2\"
eval i=\"\$numbers_$ii\"; #should be ok becauses numbers are validated at mask1 matching; i is used in arithmetic expressions
#Remove Zero's from the beginning of "i":
sign=""
if [ ! "${i#"-"}" = "$i" ]; then #i has a '-' sign
sign="-"
fi
t="${i#"$sign""0"*[1-9]}"
zeros="${i%"$t"}"
zeros="${zeros%?}" #Remove last non-0 digit
zeros="${zeros#"-"}" #Remove "-" sign
i="$sign""${i#"$sign""$zeros"}"
if [ "$crt_shell" = "dash" ]; then
arith_expr_eval=$(($arith_expr)) || arith_err_encountered="true" #halts on error; catch error output
else
eval arith_expr_eval=\$\(\($arith_expr\)\) 2>/dev/null || arith_err_encountered="true" #does not halt on error; don't catch error output
fi
if [ "$arith_err_encountered" = "false" ]; then
if [ ! "$arith_expr_padding" = "false" ]; then
arith_expr_eval_padded="$(eval printf \"\%0$arith_expr_padding_number\d\" \"$arith_expr_eval\")"
unset arith_expr_eval #zsh bug?
arith_expr_eval="$arith_expr_eval_padded"
fi
new_f_n="$new_f_n$arith_expr_eval"
else break; fi
eval new_f_n=\"\$new_f_n\$pylon2_mask2\$margin2_$ii\"
eval rn_to_$ii=\"\$new_f_n\"
done
rn_to_0=$rn_from_0
if [ "$arith_err_encountered" = "true" ]; then
printf "Arithmetic errors were encoutered: nothing done!\n\n"
CleanUp && exit 1
fi
#Check if the arithmetic expression is constant:
if [ ! "$rn_from_0" = "0" ]; then
i=1
number1=$(($arith_expr))
i=2
number2=$(($arith_expr))
if [ "$number1" = "$number2" ]; then
printf "$E: Constant arithmetic expression not allowed (=$number1)!\n\n"
CleanUp && exit 1
fi
fi
coll_err="false"
### Check for file name collision (1):
coll_chk_1_markings_0=$rn_to_0
PrintJustInTitle "A: Step 3 of 4: file name 1 of ${rn_to_0}..."
if [ "$rn_to_0" -ge "2" ]; then
prev_rn_from_fn="$rn_from_1"
prev_rn_to_fn="$rn_to_1"
fn_coll_detected="false"
for ii in $(seq 2 $rn_to_0); do
PrintJustInTitle "A: Step 3 of 4: file name $ii of ${rn_to_0}..."
eval crt_rn_from_fn=\"\$rn_from_$ii\"
eval crt_rn_to_fn=\"\$rn_to_$ii\"
if [ "$prev_rn_to_fn" = "$crt_rn_to_fn" ]; then
eval coll_chk_1_markings_$ii="1"
eval coll_chk_1_markings_$((ii-1))="1"
if [ "$fn_coll_detected" = "false" ]; then
printf '%s' "$E: File name collision: \"$prev_rn_from_fn\"; \"$crt_rn_from_fn\""
fn_coll_detected="true"
coll_err="true"
else
printf '%s' "; \"$crt_rn_from_fn\""
fi
else
if [ "$fn_coll_detected" = "true" ]; then
printf '%s\n' " -> \"$prev_rn_to_fn\""
fn_coll_detected="false"
fi
fi
prev_rn_from_fn="$crt_rn_from_fn"
prev_rn_to_fn="$crt_rn_to_fn"
done
#Treat last file separately:
if [ "$fn_coll_detected" = "true" ]; then
eval coll_chk_1_markings_$ii="1"
printf '%s\n' " -> \"$crt_rn_to_fn\""
fn_coll_detected="false"
fi
fi
### Check for temporary file name collision (2):
temp_coll_detected="false"
for j in $(seq 1 $rn_to_0); do
PrintJustInTitle "A: Step 4 of 4: file name $j of ${rn_to_0}..."
eval crt_rn_to_fn=\"\$rn_to_$j\"
eval crt_rn_from_fn=\"\$rn_from_$j\"
eval crt_coll_chk_1_marking=\"\$coll_chk_1_markings_$j\"
if [ ! "$crt_coll_chk_1_marking" = "1" ]; then
if [ -e "$crt_rn_to_fn" ]; then
if [ \( $file "$crt_rn_to_fn" \) -o \( $dir "$crt_rn_to_fn" \) ]; then
case $crt_rn_to_fn in
*"$pylon1_mask1"*[0-9]*"$pylon2_mask1"* ) #file name is match for <mask1>
ProcedureGetMarginsAndNumber crt_rn_to_fn
i=$number
eval [ \\\( $extra_cond \\\) -a \\\( $one_cond \\\) ] 2>/dev/null && {
if [ ! "$temp_coll_detected" = "true" ]; then
temp_coll_detected="true"
fi
eval marks_temp_fns_$j=\"\1\"
} || {
if [ ! "$coll_err" = "true" ]; then
coll_err="true"
fi
eval marks_temp_fns_$j=\"\0\"
printf '%s\n' "$E: file name collision: $crt_rn_from_fn -> $crt_rn_to_fn"
}
;;
esac
else
if [ ! "$coll_err" = "true" ]; then
coll_err="true"
fi
printf '%s\n' "$E: file name collision: $crt_rn_from_fn -> $crt_rn_to_fn"
fi
else
eval marks_temp_fns_$j=\"\0\"
fi
fi
done
if [ "$coll_err" = "true" ]; then
if [ "$preview_flag" = "1" ]; then
printf "\nPreview - File name collision errors were encoutered!\n\n"
else
printf "\nRename - File name collision errors were encoutered: nothing done!\n\n"
fi
CleanUp && exit 1
fi
#If no errors were encountered:
if [ "$preview_flag" = "1" ]; then
printf "Previewing rename:\n"
for i in $(seq 1 $rn_from_0); do
PrintJustInTitle "P: Step 1 of 1: file name $i of ${rn_from_0}..."
eval crt_rn_from_fn=\"\$rn_from_$i\"
eval crt_rn_to_fn=\"\$rn_to_$i\"
printf '%s\n' "$crt_rn_from_fn -> $crt_rn_to_fn"
done
else
printf "\n"
err_encoutered="false"
#Disable CTRL-C, CTRL-Z while the rename is in progress:
trap '' INT
trap '' TSTP
printf "Rename in progress.. Please do not interrupt...\n">/dev/stdin
if [ "$temp_coll_detected" = "false" ]; then
for i in $(seq 1 $rn_from_0); do
PrintJustInTitle "R: Step 1 of 1: file name $i of ${rn_from_0}..."
eval crt_rn_from_fn=\"\$rn_from_$i\"
eval crt_rn_to_fn=\"\$rn_to_$i\"
{
mv -n "./$crt_rn_from_fn" "./$crt_rn_to_fn"
}&&{
started_rn="true"
}||{
printf '%s\n' "$E: RENAMING \"$crt_rn_from_fn\" TO \"$crt_rn_to_fn\"!"
err_encoutered="true"
}
done
elif [ "$temp_coll_detected" = "true" ]; then
for i in $(seq 1 $rn_from_0); do
PrintJustInTitle "R: Step 1 of 3: file name $i of ${rn_from_0}..."
eval crt_rn_from_fn=\"\$rn_from_$i\"
eval crt_rn_to_fn=\"\$rn_to_$i\"
eval crt_marks_temp_fn=\"\$marks_temp_fns_$i\"
if [ "$crt_marks_temp_fn" = "0" ]; then
{
mv -n "./$crt_rn_from_fn" "./$crt_rn_to_fn"
}&&{
started_rn="true"
}||{
printf '%s\n' "$E: RENAMING \"$crt_rn_from_fn\" TO \"$crt_rn_to_fn\"!"
err_encoutered="true"
}
fi
done
for i in $(seq 1 $rn_from_0); do
PrintJustInTitle "R: Step 2 of 3: file name $i of ${rn_from_0}..."
eval crt_rn_from_fn=\"\$rn_from_$i\"
eval crt_rn_to_fn=\"\$rn_to_$i\"
eval crt_marks_temp_fn=\"\$marks_temp_fns_$i\"
if [ "$crt_marks_temp_fn" = "1" ]; then
if [ ! "$crt_rn_from_fn" = "$crt_rn_to_fn" ]; then #skip rename to itself cases
{
mv -n "./$crt_rn_from_fn" "./▄$crt_rn_to_fn"
}&&{
started_rn="true"
}||{
printf '%s\n' "$E: RENAMING \"$crt_rn_from_fn\" TO TEMPORARY FILE NAME \"▄$crt_rn_to_fn\"!"
err_encoutered="true"
}
fi
fi
done
for i in $(seq 1 $rn_from_0); do
PrintJustInTitle "R: Step 3 of 3: file name $i of ${rn_from_0}..."
eval crt_rn_from_fn=\"\$rn_from_$i\"
eval crt_rn_to_fn=\"\$rn_to_$i\"
eval crt_marks_temp_fn=\"\$marks_temp_fns_$i\"
if [ "$crt_marks_temp_fn" = "1" ]; then
if [ ! "$crt_rn_from_fn" = "$crt_rn_to_fn" ]; then #skip rename to itself cases
#started_rn is "true"
{
mv -n "./▄$crt_rn_to_fn" "./$crt_rn_to_fn"
}||{
printf '%s\n' "$E: RENAMING TEMPORARY FILE NAME \"▄$crt_rn_to_fn\" TO \"$crt_rn_to_fn\"!"
err_encoutered="true"
}
fi
fi
done
fi
printf "\n\nRename done.\n">/dev/stdin
fi
PrintJustInTitle "Done. Cleaning up..."
CleanUp
fi
MAIN END