我有以下目录结构:
.
├── event-a
│ ├── album-a
│ │ ├── a.jpg
│ │ └── x.png
│ └── album-b
│ ├── a.jpg
│ ├── x.png
│ └── y.gif
└── event-b
├── album-x
│ ├── a.jpg
│ └── x.png
└── album-y
├── a.jpg
├── x.png
└── y.gif
对于每个二级子文件夹(album-foo
在示例中命名),我想按名称对文件进行排序,并将它们重命名为连续的填充数字,无论其扩展名如何。这些文件夹可能包含 JPG、PNG 或 GIF 图像,并且应保留所有文件扩展名。
所以,在这种情况下,我想得到这样的结果:
.
├── event-a
│ ├── album-a
│ │ ├── 01.jpg
│ │ └── 02.png
│ └── album-b
│ ├── 01.jpg
│ ├── 02.png
│ └── 03.gif
└── event-b
├── album-x
│ ├── 01.jpg
│ └── 02.png
└── album-y
├── 01.jpg
├── 02.png
└── 03.gif
实用性rename
如果这能让事情变得更容易的话,可以使用。
主要问题是弄清楚每个文件应该获得的数量。我是否需要使用嵌套for
循环来迭代event-x
和album-x
子文件夹,然后对于每个内部循环,自己跟踪数字,或者是否有一些我缺少的聪明的解决方案?
答案1
for dir in */*; do # loop over the directories
( # run in a subshell ...
cd "$dir" # ... so we don't have to cd back
files=(*) # store the filenames in a zero-indexed array
for index in "${!files[@]}"; do
file=${files[$index]}
ext=${file##*.}
newname=$(printf "%02d.%s" $((index+1)) "$ext")
mv "$file" "$newname"
done
)
done
假设您有一个没有扩展名的文件。在这种情况下,除了前导数字之外,它将具有相同的名称(例如my_file
=> 05.my_file
)
所有非隐藏目录条目都将被重命名,包括目录。
答案2
您这里有两组问题:
- 递归到目录中。
- 在每个单独的目录中重新启动编号系统。
这将顺利处理这两种情况,但如果您决定还包含其他扩展,则需要修改 IMAGE_TYPES 变量。
#!/bin/bash
shopt -s extglob
shopt -s nocaseglob
IMAGE_TYPES='jpg|png|gif'
IFS=$'\n' dirlist=(`find "$PWD" -type d`)
for dir in "${dirlist[@]}"; do
cd "$dir"
ls *.+($IMAGE_TYPES) > /dev/null 2>&1 || continue
counter=0
for file in *.+($IMAGE_TYPES); do
printf -v newname "%.3d.%s" $((counter += 1)) "${file##*.}"
mv --verbose "$file" "$newname"
done
done
答案3
我创建了同一棵树并进行了您的移动构建。这是我想出的:
n=0 IFS=.; set -f ./[e]vent*/*/*
for f do [ -n "${f##./\[*}" ] || break
[ "$d" = "${f%/*}" ] || i=0 d=${f%/*}
mv=': mv "${'$((n=$n+1))'}" "${'$n'%%/*}/'
printf "$mv%.2d%.0s.%s\"\n" $((i=$i+1)) ${f##*/}
done | sh -sx -- "$@"
如果没有最后一个|
管道,那么它会打印出以下内容:
mv "${1}" "${1%/*}/01.jpg"
mv "${2}" "${2%/*}/02.png"
mv "${3}" "${3%/*}/01.jpg"
mv "${4}" "${4%/*}/02.png"
mv "${5}" "${5%/*}/03.gif"
mv "${6}" "${6%/*}/01.jpg"
mv "${7}" "${7%/*}/02.png"
mv "${8}" "${8%/*}/01.jpg"
mv "${9}" "${9%/*}/02.png"
mv "${10}" "${10%/*}/03.gif"
我知道,它看起来并不多,但这里重要的是您不必担心任何奇怪的文件名或任何其他内容 - 该输出的预期目的地是与循环共享位置数组的for
shell产生它的。我在命令中有一个这样的命令 - 它被配置为提供调试输出,如下所示:
+ : mv ./event-a/album-a/a.jpg ./event-a/album-a/01.jpg
+ : mv ./event-a/album-a/x.png ./event-a/album-a/02.png
+ : mv ./event-a/album-b/a.jpg ./event-a/album-b/01.jpg
+ : mv ./event-a/album-b/x.png ./event-a/album-b/02.png
+ : mv ./event-a/album-b/y.gif ./event-a/album-b/03.gif
+ : mv ./event-b/album-x/a.jpg ./event-b/album-x/01.jpg
+ : mv ./event-b/album-x/x.png ./event-b/album-x/02.png
+ : mv ./event-b/album-y/a.jpg ./event-b/album-y/01.jpg
+ : mv ./event-b/album-y/x.png ./event-b/album-y/02.png
+ : mv ./event-b/album-y/y.gif ./event-b/album-y/03.gif
:
这就是当是格式字符串中的第一个字符时的样子printf
。当我删除它并执行命令时:
ls ./event*/*/
./event-a/album-a/:
01.jpg 02.png
./event-a/album-b/:
01.jpg 02.png 03.gif
./event-b/album-x/:
01.jpg 02.png
./event-b/album-y/:
01.jpg 02.png 03.gif
这似乎符合您的要求。我想你无法打败结果。
答案4
如果您知道文件的名称,则可以通过运行以下命令获取它的编号:
ls -1 <your_dir> | grep <file_name> -B 1000 | wc -l