我有一个目录结构,其中目录和文件命名错误,我需要修改名称。目录有子目录,这些子目录只有文件。
在这个树中,我需要按照下表重命名文件和子目录。例如,名为hdm
的目录应重命名为hdu
。根据下面的转换表,名为hdm_e_01.png
的文件应重命名为hdu_e_01.png
。
但是,请注意,这需要分两个阶段进行,因为已经有一个名为hdu
的目录,需要根据表重命名为hds
,再加上新重命名的目录{ {1}}需要保持为hdu
而不是更改为hdu
。因此,第一阶段需要将它们全部重命名为非冲突的临时和第二阶段的最终名称。
hds
答案 0 :(得分:1)
首先,重命名目录:
cd /to/your/root/dir
cp -R hda /some/tmp/dir/hdx
cp -R hde /some/tmp/dir/hdw
cp -R hdi /some/tmp/dir/hdv
...
现在重命名您的文件:
cd /some/tmp/dir/
for d in "$(find . -type d -name 'hd*')" ; do
cd "${d}"
for f in *; do
mv "${f}" "${d}${f:3}"
done
cd ..
done
基本上它遍历你的目录,并根据目录名称,按照你的规范重命名那里的文件,除了它不检查哪些是从文件名的开头删除的3个字符。
所以我建议在echo
行前添加mv
,例如:
echo mv "${f}" "${d}${f:3}"
然后首先检查输出。
如果您对结果满意,请执行重命名,然后删除原件并将修改后的目录移动到原位。
然后有像mmv
这样的解决方案,但不是基础bash
标准。
答案 1 :(得分:0)
我感谢你提出的有趣问题。这是我的解决方案。
#!/bin/bash
TABLE_FILE='file.table'
DIRECTORY='.'
PRETEND=true ## Set to false to change files.
declare -A RMAP=() FLAGS=() RENAMED=() NEWPATHS=()
declare -a ORDER=()
function check_directory {
if [[ ! -d $DIRECTORY ]]; then
echo "Directory does not exist: $DIRECTORY"
return 1
fi
return 0
}
function parse_table_file {
local -A F=() T=()
local -i I=0
if [[ ! -f $TABLE_FILE || ! -r $TABLE_FILE ]]; then
echo "Table file does not exist or is not readable: $TABLE_FILE"
return 1
fi
while read FROM TO; do
if [[ -n ${F[FROM]} ]]; then
echo "We can't have two the same sources: $FROM"
return 1
fi
if [[ -n ${T[TO]} ]]; then
echo "We can't have two them same replacements: $TO"
return 1
fi
RMAP[$FROM]=$TO ORDER[I++]=$FROM F[$FROM]=. T[$TO]=.
done < "$TABLE_FILE"
return 0
}
function rename {
local FROM=$1 TO=$2
if [[ ${FLAGS[$FROM]} != R ]]; then
if [[ ${FLAGS[$TO]} == H ]]; then
echo "Circular rename point detected: $FROM - $TO"
return 1
elif [[ -n ${RMAP[$TO]} ]]; then
FLAGS[$FROM]=H
rename "$TO" "${RMAP[$TO]}" || return 1
fi
local -a TARGETS=("$DIRECTORY/$FROM"*)
local NEWNAME NEWPATH
for TARGET in "${TARGETS[@]}"; do
NEWNAME=${TO}${TARGET##**"/${FROM}"}
NEWPATH=${DIRECTORY}/${NEWNAME}
echo "Renaming $TARGET to $NEWNAME ($NEWPATH)."
if [[ -n ${NEWPATHS[$NEWPATH]} ]]; then
echo "$TO has had same file matches as the previous ones: $NEWPATH through pattern ${NEWPATHS[$NEWPATH]}."
return 1
fi
if [[ -e $NEWPATH ]]; then
if [[ -n ${RENAMED[$NEWPATH]} ]]; then
if [[ $PRETEND == false ]]; then
echo "Can't rename $TARGET to $NEWNAME ($NEWPATH): file still exists and should have been renamed already with previous set ${RENAMED[$NEWPATH]}."
return 1
fi
else
echo "Can't rename $TARGET to $NEWNAME ($NEWPATH): file already exists and is not part of the renaming sequence."
return 1
fi
fi
if [[ $PRETEND == false ]]; then
mv "$TARGET" "$NEWPATH" || {
echo "Failed to rename $NEWNAME to $NEWPATH."
return 1
}
fi
NEWPATHS[$NEWPATH]=$TO
RENAMED[$TARGET]="$FROM - $TO"
done
FLAGS[$FROM]=R
fi
return 0
}
function process {
for FROM in "${ORDER[@]}"; do
rename "$FROM" "${RMAP[$FROM]}" || return 1
done
return 0
}
check_directory && parse_table_file && process
该脚本使用递归来解决和检测冲突,而无需临时重命名。它还可以假装重命名以查看如果已经进行了更改将会发生什么,并防止出错。
示例我有这些文件:
aaa (D)
aab (D)
aaa.txt (F)
然后我在桌子上有这些线:
aaa aab
aab aac
这是我的输出:
Renaming ./aab to aac (./aac).
Renaming ./aaa to aab (./aab).
Renaming ./aaa.txt to aab.txt (./aab.txt).