If you save the next script as renn.sh
, after installing it (see help for how to install it), you should be able to use:
renn "@." "[(02)i+1]." "{i -ge 5}" '<dir_path>'
To find out how to use the script, you can call it with the --help
flag.
# 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 ##