![将目录中的所有文件小写,期望在某个时候撤消它](https://linux22.com/image/863489/%E5%B0%86%E7%9B%AE%E5%BD%95%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E6%96%87%E4%BB%B6%E5%B0%8F%E5%86%99%EF%BC%8C%E6%9C%9F%E6%9C%9B%E5%9C%A8%E6%9F%90%E4%B8%AA%E6%97%B6%E5%80%99%E6%92%A4%E6%B6%88%E5%AE%83.png)
好的,我想批量重命名目录中的文件(以及子目录中的文件)为小写,但我还想在某个时候撤消该操作。我是否应该将它们的真实名称存储在某个地方,以便完成后可以返回原始结构?
这可以在 bash 中完成吗?
答案1
是的,很简单
for f in *; do
mv "$f" "${f,,}"
printf "mv %q %q\n" "${f,,}" "$f" >> restore.sh
done
运行bash restore.sh
以恢复以前的文件名。
递归:比第一次出现时更棘手:我最终分别处理了文件和目录,只重命名了路径的基本部分。
declare -A restore=([f]=restore_file.sh [d]=restore_dir.sh)
for type in f d; do
find . -type $type -print0 | while IFS= read -rd '' path; do
base=$(basename "$path")
lower="$(dirname "$path")/${base,,}"
mv "$path" "$lower"
printf "mv %q %q\n" "$lower" "$path" >> "${restore[$type]}"
done
done
恢复:
bash restore_dir.sh
bash restore_file.sh
答案2
重命名非常简单,只需使用 进行一点变换即可rename
。以下是无效的(删除 -n 标志以使其执行操作),它会告诉您它在做什么:
rename 'tr/A-Z/a-z/' -vn *
但是,如果您想将其构建成可逆脚本,您还需要做更多的事情:
rename 'tr/A-Z/a-z/' -vn * | sed 's/ renamed as /#/' | awk -F'#' '{print "mv '\''" $2 "'\'' '\''" $1 "'\''"}' > reverse.sh
如果您需要更改进入此列表的文件(例如递归),您可以通过管道将名称重命名:
find | rename ...
或者使用一些 Bash 选项进行递归遍历:
shopt -s globstar
rename ... ** *
答案3
#!/bin/bash
IFS=$'\n'
WORKING_PATH=$(pwd $1)
RESTORE_FILENAME="$WORKING_PATH/restore_case.sh"
echo "#!/bin/bash" > "$RESTORE_FILENAME"
chmod a+x "$RESTORE_FILENAME"
for FILEPATH in $(find . -type f)
do
FILENAME="${FILEPATH##*/}"
LOWER_FILE="${FILEPATH::-${#FILENAME}}${FILENAME,,}"
if [ "$LOWER_FILE" != "$FILEPATH" ]; then
echo moving "$FILEPATH" to "$LOWER_FILE"
echo mv \""$LOWER_FILE"\" \""$FILEPATH"\" >> "$RESTORE_FILENAME"_files
mv "$FILEPATH" "$LOWER_FILE"
fi
done
touch "$RESTORE_FILENAME"_dirs
for DIRPATH in $(find . -type d -printf "%d%p\n"|sort -nr)
do
DIRPATH=${DIRPATH:1}
DIRNAME="${DIRPATH##*/}"
LOWER_DIRPATH="${DIRPATH::-${#DIRNAME}}${DIRNAME,,}"
if [ "$LOWER_DIRPATH" != "$DIRPATH" ]; then
echo moving "$DIRPATH" to "$LOWER_DIRPATH"
echo -e "mv \""$LOWER_DIRPATH"\" \""$DIRPATH"\"\n$(cat "$RESTORE_FILENAME"_dirs)" > "$RESTORE_FILENAME"_dirs
mv "$DIRPATH" "$LOWER_DIRPATH"
fi
done
cat "$RESTORE_FILENAME"_dirs "$RESTORE_FILENAME"_files >> "$RESTORE_FILENAME"
rm "$RESTORE_FILENAME"_dirs "$RESTORE_FILENAME"_files
echo rm '$0' >> "$RESTORE_FILENAME"
更长,有点脏,但更精确,也不会做不必要的mv