假设您的图像文件名不包含空格并且您的文件夹名称不包含空格(因此无需极端滑稽动作来处理极其尴尬的文件名),那么您可以考虑:
find "$directory" -type f -iname 'IMG_[0-9][0-9][0-9][0-9].jpg' -print |
while read file
do
base=$(basename "$file")
dir=$(dirname "$file")
bdir=$(basename "$dir")
suffix=$(echo "$base" | sed 's/^[Ii][Mm][Gg]_//')
mv "$file" "$dir/$bdir$suffix"
done
我没有说任何关于效率的事情。由于您没有使用 Bash 或 Ksh 对其进行标记,因此我没有假设他们有任何用于变量编辑的工具。除了使用$(…) 代替反引号`…` 和find 的-iname 选项外,这基本上适用于过去20 年左右从Bourne shell 派生的任何shell。
如果您决定在目录或文件名中需要空格等,则需要查看代码。它很可能是安全的(因为它在变量引用周围使用双引号,例如"$file"),但您需要真正担心您的文件名或目录名是否可以包含换行符。
使用您的方法,我现在已经找到了重命名这些文件的方法。但是,当我根据它们的目录重命名它们时,我正在覆盖每个文件并丢失许多文件。有没有办法避免这种情况,例如在文件名的末尾添加数字?
- 通过在
mv 前面加上echo 进行测试,这样您就知道会发生什么,而无需实际发生。
- 我认为您必须修改了代码或与合理推断的情况略有不同。下面有一个示例,其中包含一组全新的垃圾目录层次结构中的空文件。每个目录的输入名称都是唯一的;每个目录的输出名称都是唯一的;除非目录中已经存在使用修改后的命名方案的文件,否则脚本无法生成冲突和丢失数据。即使您将文件上移一级,名称也应该是唯一的,因为子目录首先是唯一的。
示例运行:
$ mkdir junk
$ cd junk
$ for dir in primary secondary tertiary
> do (mkdir $dir; cd $dir; touch $(seq -f 'IMG_%04.0f.jpg' 1 10))
> done
$ ls
primary secondary tertiary
$ ls *
primary:
IMG_0001.jpg IMG_0002.jpg IMG_0003.jpg IMG_0004.jpg IMG_0005.jpg IMG_0006.jpg IMG_0007.jpg IMG_0008.jpg IMG_0009.jpg IMG_0010.jpg
secondary:
IMG_0001.jpg IMG_0002.jpg IMG_0003.jpg IMG_0004.jpg IMG_0005.jpg IMG_0006.jpg IMG_0007.jpg IMG_0008.jpg IMG_0009.jpg IMG_0010.jpg
tertiary:
IMG_0001.jpg IMG_0002.jpg IMG_0003.jpg IMG_0004.jpg IMG_0005.jpg IMG_0006.jpg IMG_0007.jpg IMG_0008.jpg IMG_0009.jpg IMG_0010.jpg
$ directory=.
$ find "$directory" -type f -iname 'IMG_[0-9][0-9][0-9][0-9].jpg' -print |
> while read file
> do
> base=$(basename "$file")
> dir=$(dirname "$file")
> bdir=$(basename "$dir")
> suffix=$(echo "$base" | sed 's/^[Ii][Mm][Gg]_//')
> mv "$file" "$dir/$bdir$suffix"
> done
$ ls
primary secondary tertiary
$ ls *
primary:
primary0001.jpg primary0003.jpg primary0005.jpg primary0007.jpg primary0009.jpg
primary0002.jpg primary0004.jpg primary0006.jpg primary0008.jpg primary0010.jpg
secondary:
secondary0001.jpg secondary0003.jpg secondary0005.jpg secondary0007.jpg secondary0009.jpg
secondary0002.jpg secondary0004.jpg secondary0006.jpg secondary0008.jpg secondary0010.jpg
tertiary:
tertiary0001.jpg tertiary0003.jpg tertiary0005.jpg tertiary0007.jpg tertiary0009.jpg
tertiary0002.jpg tertiary0004.jpg tertiary0006.jpg tertiary0008.jpg tertiary0010.jpg
$
当我在每个目录中创建 1000 个文件并计时移动时,重命名这 3000 个文件需要 46 秒(在带有硬盘且没有 SSD 的 Mac OS X 10.10.4 上运行)。这比我预期的要长一点。
修改脚本如下所示,将每个目录 1000 个文件的运行时间缩短为 8 秒(从 46 秒),速度提高了大约 5 秒。这是一个值得改进的地方,但仍然感觉脚本运行速度没有那么快就像现代 Linux 一样——但这可能是古老机器、硬盘、HTFS 文件系统和 Mac OS X 开销的组合(例如,窗口的标题栏会在脚本运行时更改当前运行的命令名称) .
directory='.'
time find "$directory" -type f -iname 'IMG_[0-9][0-9][0-9][0-9].jpg' -print |
while read file
do
#base=$(basename "$file")
base=${file##*/}
#dir=$(dirname "$file")
dir=${file%/*}
#bdir=$(basename "$dir")
bdir=${dir#*/}
#suffix=$(echo "$base" | sed 's/^[Ii][Mm][Gg]_//')
suffix=${base/[Ii][Mm][Gg]_/}
mv "$file" "$dir/$bdir$suffix"
done
为了进一步改进,我会使用 Perl 并让它作为系统调用执行重命名操作,而不是调用单独的程序。这将减少更多的进程开销(修改后的脚本中仍有 3000 个mv 命令,而 Perl 或等效的整个移动只有一个进程)。
请注意,参数替换是有效的,因为名称被限制为行为良好(每个名称中至少有一个斜线;未命名根目录等)。由basename 和dirname 命令处理的边缘情况不会由参数替换处理。谨慎概括。