Bash - 递归目录/文件重命名

Bash - 递归目录/文件重命名

我有以下脚本,它将递归地替换文件和目录中的所有空格:

################### SETUP VARIABLES #######################
number=0                    # Number of renamed.
number_not=0                # Number of not renamed.
IFS=$'\n'
array=( `find ./ -type d` ) # Find catalogs recursively.


######################## GO ###############################
# Reverse cycle.
for (( i = ${#array[@]}; i; )); do
     # Go in to catalog.
     pushd "${array[--i]}" >/dev/null 2>&1
     # Search of all files in the current directory.
     for name in *
     do
             # Check for spaces in names of files and directories.
             echo "$name" | grep -q " "
             if [ $? -eq 0 ]
             then
                # Replacing spaces with underscores.
                newname=`echo $name | sed -e "s/ /_/g"`
                if [ -e $newname ]
                then
                        let "number_not +=1"
                        echo " Not renaming: $name"
                else
                        # Plus one to number.
                        let "number += 1"
                        # Message about rename.
                        echo "$number Renaming: $name"
                        # Rename.
                        mv "$name" "$newname"
                fi
             fi
     done
     # Go back.
     popd >/dev/null 2>&1
done

echo -en "\n All operations is complited."

if [ "$number_not" -ne "0" ]
  then echo -en "\n $number_not not renamed."
fi

if [ "$number" -eq "0" ]
  then echo -en "\n Nothing been renamed.\n"
elif [ "$number" -eq "1" ]
   then echo -en "\n $number renamed.\n"
   else echo -en "\n Renamed files and catalogs: $number\n"
fi

exit 0

它的工作原理是用目录填充数组:

array=( `find ./ -type d` ) # Find catalogs recursively.

如果我想强制这个脚本在特定目录中工作,我可以这样做吗?

array=( `find /my/start/directory/ -type d` ) # Find catalogs recursively.

我在这里询问(而不是仅仅运行它),因为我想仔细检查它是否正确,我不想意外地重命名服务器上的每个文件!

答案1

您可以通过注释掉命令mv并运行它来测试您建议的更改的脚本。脚本中发生的事情太多了,我无法立即说没问题,但是如果当前脚本有效(显然没有包含换行符的目录名称,或者数组array将被破坏,或者名称从破折号开始,这可能会造成混淆mv,并且echo在一些地方)然后我冒险猜测它会没问题。


递归地将目录和其他文件的文件名中的空格替换为下划线:

topdir=.
find "$topdir" -depth -name "* *" -exec bash -c '
    for pathname do
        # $pathname will have at least one space in it
        newname=${pathname##*/}  # get basename
        newname=${newname// /_}  # replace spaces with underscores
        printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
        # mv "$pathname" "${pathname%/*}/$newname"
     done' bash {} +

这将找到$topdir其名称中或下方至少包含一个空格的任何内容。它会收集这些路径名并将它们提供给内联bash脚本。该脚本将提取每个路径名的文件名部分,并用下划线替换空格。为了安全起见,实际mv操作被注释掉。

-depth选项在这里是必要的,因为我们不想重命名尚未访问的目录。有了它,find将对目录层次结构进行深度优先遍历。

使用的参数替换:

  • ${variable##*/}:删除 值中最后一个斜杠之前的所有内容variable。或多或少与 相同$( basename "$variable" )
  • ${variable%/*}: 删除最后一个斜杠之后的所有内容。或多或少与 相同$( dirname "$variable" )
  • ${variable//pattern/replacement}:替换值中pattern与匹配的所有内容(这是扩展)replacementvariablebash

不检查新文件名是否已存在。这可以很容易地在内部脚本中完成bash,例如

if [ -e "${pathname%/*}/$newname" ]; then
    printf "Will not rename %s, new name exists\n" "$pathname" >&2
else
    printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
    # mv "$pathname" "${pathname%/*}/$newname"
fi

测试:

$ tree
.
|-- a directory
|   `-- yet another file
|-- script.sh
|-- some file
`-- some other file

1 directory, 4 files

$ sh script.sh
Would move ./some file to ./some_file
Would move ./some other file to ./some_other_file
Would move ./a directory/yet another file to ./a directory/yet_another_file
Would move ./a directory to ./a_directory

有关的:

相关内容