Rename pairs of link files in the shell. Rename by multiple pairs of link file names.
#!/bin/bash
# The bubbles in the asset markets
# are equivalent to various taxes,
# payed by each of us in the long term,
# whether a winner or loser in the game.
# Features:
# Change a pair of link files
# from
# link1.old -> target1.old
# to
# link1.new -> target1.new
# Rename by multiple pairs of link file names
# A lightweight alternative to other heavy tools.
# Dependency:
# The `realpath` package is required
# Use the commands of `mv`,`ln`,`rm` etc. underlyingly.
# Usage:
# Link and target files should have the same new name,
# but not necessarily the same old name.
# 1. Rename link/target by one pair of file names:
# ./rename_linkets.bash link_old_path new_name
# The link_old_path could be in the format of:
# ./old_link.yy or old_link.yy
# ./old_link or old_link
# ~/old_link
# /path/to/old_link
# The new_name should be the file/dir name that would be changed to
# and shouldn't include the upper level parent path
# 2. Rename files by multiple pairs of file names:
# ./rename_linkets.bash "old_link1 old_link2 .." "new_name1 new_name2 .."
# The number of old_link files should be the same as new names:
# ./rename_linkets.bash "./{link1,link2}" "new_name1 new_name2"
# ./rename_linkets.bash "./{link1,link2} c1" "new_name1 new_name2 c2"
# Linket:
# A pair of files for linking, that work in the form of:
# Link file -> Target file
# #!/bin/bash
#
# # Test the usage of rename_linkets.bash
# # Operation on some files would fail on purpose
# # to show failure cases
#
# # use ./test_rename_linkets.bash -o
# # to override the check on the test dir/files
#
# echo_start(){
# echo "Start test $1 ============================="
# }
#
# init(){
# echo_start "$1"
# rm -r ./test9
# mkdir -p ./test9/dir1 ./test9/dir2
# }
#
# run_tests(){
# if [[ -e ./test9 && "-o" != "$option" ]]
# then
# echo "Dir test9 existed. Quit."
# exit 1
# fi
#
# for test in "$@"
# do
# init "$test"
# $test
# done
# }
#
# test1(){
# touch ./test9/b.o
# touch ./test9/dir2/r.o
#
# ln -s ../dir2/t.o ./test9/dir1/t.o
# ln -s "../dir2/r.o" ./test9/dir1/r.o
#
# ./rename_linkets.bash "./test9/a.o test9/b.o ./test9/dir1/{t.o,r.o}" "a.n b.n t.n r.n"
# }
#
# test2(){
# if [ "-o" != "$option" ]
# then
# for f in `echo "u.o u.n"`
# do
# echo "File $f existed. Quit."
# exit 1
# done
# fi
#
# rm u.o u.n ./test9/u.o
# touch ./test9/u.o
# ln -s ./test9/u.o u.o
# ./rename_linkets.bash u.o u.n
# }
#
# test3(){
# # test dangerous path
# touch ./test9/dir2/dg.o
# ln -s ../dir2/dg.o ./test9/dir1/dg.o
# ./rename_linkets.bash ./test9/dir1/dg.o dg.n
# }
#
# option="$1"
#
# #run_tests test1
# #run_tests test2
# #run_tests test3
# run_tests test1 test2
#
echo "Start script ----------------------"
# f1: old link file or old target file
# of the linket (link pair)
# f2: new link file or new target file
# of the linket (link pair)
# Linket: a pair of files for linking, that work in the form of:
# Link file -> Target file
# Raw path format: ~/dir{1,2}/
# expanded path format: /home/user/dir1/ /home/user/dir2/
# fine path format: /home/user/dir1 /home/user/dir2
check_dependency(){
rslt=$(realpath --version)
bin_name="${rslt:0:8}"
if [ "realpath" != "$bin_name" ]
then
echo "ERR:: Require the package of realpath, but realpath is not found."
echo " To install realpath, run the command of:"
echo " sudo apt-get update && sudo apt-get install realpath"
echo " Exit."
exit 1
fi
}
expand_path(){
# raw path format: ~/s1 /y/tt1/ t1 ~/{s1,s2}
str_expanded_paths_of_f1="$(eval echo $str_raw_paths_of_f1)"
#echo "str_expanded_paths_of_f1:" $str_expanded_paths_of_f1
}
check_nums_of_path_and_name(){
arr_expanded_paths_of_f1=($str_expanded_paths_of_f1)
arr_names_of_f2=($str_names_of_f2)
#echo "arr_expanded_paths_of_f1: ${arr_expanded_paths_of_f1[@]}"
if [ ${#arr_expanded_paths_of_f1[@]} -ne ${#arr_names_of_f2[@]} ]
then
echo "ERR:: The number of old files and the number of new names"
echo "ERR:: are not matched."
exit 1
fi
}
check_arg_nums(){
length_arglist_raw=$#
if [ 2 -gt $length_arglist_raw ]
then
echo "ERR:: Lacking operand for $0"
exit 1
fi
check_nums_of_path_and_name
}
check_if_link_file_exist(){
expanded_f1_path="$1"
# tricky test conditions here.
if [ -h "$expanded_f1_path" ]
then
# -a not work here, use -e
if [ ! -e "$expanded_f1_path" ]
then
target_path=$(readlink -m "$expanded_f1_path")
echo "NOTICE:: Broken link: $expanded_f1_path -> $target_path"
return 1
fi
return 0
fi
if [ ! -f "$expanded_f1_path" ]
then
echo "NOTICE:: Couldn' find linket link file for path: $expanded_f1_path"
return 1
fi
if [ -f "$expanded_f1_path" ]
then
echo "NOTICE:: Not a linket link file, but a regular file: $expanded_f1_path"
return 1
fi
}
check_if_is_dangerous_path(){
fpath="$1"
ftype="$2"
# 1 means "no danger", 0 means "has danger"
path_has_danger=1
dangerous_path_list=("/")
#dangerous_path_list=("~/data_mnt/_____data/linux/command_tool/mv/rename_linkets/test9/dir1/dg.o")
for dangerous_path in "${dangerous_path_list[@]}"
do
if [ "$dangerous_path" == "$fpath" ]
then
path_has_danger=0
info="$2 old path has dangerous path "$dangerous_path" in : $fpath"
echo "ERR:: $info. Exit."
exit 1
fi
done
}
make_f2path_by_f1path_f2name(){
# make f2path for either link or target
# by their f1path and new name
f1_path=$1
f2_name=$2
f1_parent_path=${f1_path%/*}
f2_path=$f1_parent_path/$f2_name
}
make_paths_of_linket_link(){
make_f2path_by_f1path_f2name "$f1_path_of_link" "$f2_name"
f2_path_of_link=$f2_path
ftype="Linket-link"
check_if_is_dangerous_path "$f1_path_of_link" "$ftype"
}
make_paths_of_linket_target(){
f1_path_of_target=$(realpath "$f1_path_of_link")
make_f2path_by_f1path_f2name "$f1_path_of_target" "$f2_name"
f2_path_of_target=$f2_path
ftype="Linket-target"
check_if_is_dangerous_path "$f2_path_of_target" "$ftype"
}
make_paths_of_linket(){
# Linket: a pair of files for linking, that work in the form of:
# Link file -> Target file
f1_path_of_link=$(realpath -s "$1")
f2_name=$2
make_paths_of_linket_link
make_paths_of_linket_target
}
make_paths_of_linket_in_oneloop(){
make_paths_of_linket "$expanded_f1_path" "$f2_name"
# keey the arr for future debug info
arr_f1_paths_of_link[$i]=$f1_path_of_link
arr_f2_paths_of_link[$i]=$f2_path_of_link
arr_f1_paths_of_target[$i]=$f1_path_of_target
arr_f2_paths_of_target[$i]=$f2_path_of_target
}
mv_target_file(){
cmd="mv $f1_path_of_target $f2_path_of_target"
}
ln_new_target_file(){
cmd="ln -s $f2_path_of_target $f2_path_of_link"
}
rm_old_link_file(){
cmd="rm $f1_path_of_link"
}
do_linket_by_steps(){
do_file_steps=("mv_target_file" "ln_new_target_file" "rm_old_link_file")
for make_cmd_by_step in "${do_file_steps[@]}"
do
$make_cmd_by_step
printf "$cmd \n"
if ! $cmd
then
echo "NOTICE:: Operation failed."
return 1
fi
done
}
rename_linkets(){
length=${#arr_names_of_f2[@]}
for (( i=0; $i<$length; i++ ))
do
echo $i
f2_name=${arr_names_of_f2[$i]}
expanded_f1_path="${arr_expanded_paths_of_f1[$i]}"
check_if_link_file_exist "$expanded_f1_path"
if [ 0 -ne $? ]
then
continue
fi
make_paths_of_linket_in_oneloop
do_linket_by_steps
done
#echo "arr_f1_paths_of_target:" ${arr_f1_paths_of_target[@]}
}
main(){
check_dependency
str_raw_paths_of_f1="$1"
str_names_of_f2="$2"
expand_path
check_arg_nums "$@"
rename_linkets
}
####################################
main "$@"
#!/bin/bash
# Test the usage of rename_linkets.bash
# Operation on some files would fail on purpose
# to show failure cases
# use ./test_rename_linkets.bash -o
# to override the check on the test dir/files
echo_start(){
echo "Start test $1 ============================="
}
init(){
echo_start "$1"
rm -r ./test9
mkdir -p ./test9/dir1 ./test9/dir2
}
run_tests(){
if [[ -e ./test9 && "-o" != "$option" ]]
then
echo "Dir test9 existed. Quit."
exit 1
fi
for test in "$@"
do
init "$test"
$test
done
}
test1(){
touch ./test9/b.o
touch ./test9/dir2/r.o
ln -s ../dir2/t.o ./test9/dir1/t.o
ln -s "../dir2/r.o" ./test9/dir1/r.o
./rename_linkets.bash "./test9/a.o test9/b.o ./test9/dir1/{t.o,r.o}" "a.n b.n t.n r.n"
}
test2(){
if [ "-o" != "$option" ]
then
for f in `echo "u.o u.n"`
do
echo "File $f existed. Quit."
exit 1
done
fi
rm u.o u.n ./test9/u.o
touch ./test9/u.o
ln -s ./test9/u.o u.o
./rename_linkets.bash u.o u.n
}
test3(){
# test dangerous path
touch ./test9/dir2/dg.o
ln -s ../dir2/dg.o ./test9/dir1/dg.o
./rename_linkets.bash ./test9/dir1/dg.o dg.n
}
option="$1"
#run_tests test1
#run_tests test2
#run_tests test3
run_tests test1 test2